1. Cú pháp cơ bản của switch...case
Câu lệnh switch trong C/C++ yêu cầu biểu thức điều khiển phải là kiểu nguyên (như int, char, enum, v.v.), không hỗ trợ kiểu thực (float, double) hay chuỗi ký tự.
switch (biểu_thức) {
case hằng_số_1:
// khối lệnh
break;
case hằng_số_2:
// khối lệnh
break;
default:
// khối lệnh mặc định
break;
}
2. Sự khác biệt giữa C và C++
Trong C++, việc khai báo biến trong khối case mà không có dấu ngoặc nhọn bao quanh sẽ gây lỗi biên dịch do vi phạm quy tắc khởi tạo biến. Trong khi đó, C cho phép điều này nhưng vẫn không khuyến khích.
3. Phân tích mã máy của switch...case
Khi số lượng case ít, trình biên dịch thường chuyển đổi switch thành chuỗi các lệnh if-else if. Nếu thiếu break, luồng thực thi sẽ "rơi xuyên" (fall-through) sang các case tiếp theo — điều này xảy ra vì các khối lệnh được sắp xếp liên tiếp trong bộ nhớ, và không có rào cản điều khiển luồng nào ngăn việc thực thi tiếp theo.
4. Tối ưu bằng bảng nhảy (jump table)
Khi số lượng case đủ lớn và giá trị các nhãn case gần kề nhau, trình biên dịch áp dụng kỹ thuật "bảng nhảy" để tăng tốc độ thực thi bằng cách đánh đổi không gian bộ nhớ.
Cơ chế hoạt động như sau:
- Tạo một mảng liên tục trong bộ nhớ, mỗi phần tử lưu địa chỉ bắt đầu của một khối
case. - Tại thời điểm chạy, tính hiệu số giữa giá trị
switchvà giá trị nhỏ nhất trong cáccase. - Nếu hiệu số nằm ngoài khoảng hợp lệ (lớn hơn số lượng
case- 1), nhảy đếndefault. - Nếu hợp lệ, dùng hiệu số làm chỉ mục để truy cập trực tiếp vào bảng nhảy và nhảy đến khối lệnh tương ứng.
Ví dụ mã assembly minh họa:
mov eax, [a] ; nạp giá trị biến a
sub eax, 100 ; trừ đi giá trị case nhỏ nhất (100)
cmp eax, 3 ; so sánh với số case - 1 (ở đây có 4 case: 100–103)
ja default_label ; nếu vượt quá, nhảy đến default
jmp [jump_table + eax*4] ; nhảy gián tiếp qua bảng nhảy
Bảng nhảy jump_table chứa các địa chỉ như:
dd offset case_100
dd offset case_101
dd offset case_102
dd offset case_103
5. Khi nào không dùng bảng nhảy?
Nếu các giá trị case phân tán quá rộng (ví dụ: 1, 1000, 50000), việc tạo bảng nhảy sẽ lãng phí bộ nhớ do phải lấp đầy các khe trống bằng địa chỉ của default hoặc mã không hợp lệ. Trong trường hợp này, trình biên dịch sẽ quay lại sử dụng chuỗi so sánh tuần tự hoặc cây nhị phân tìm kiếm thay vì bảng nhảy.