Câu lệnh if
Sau bài này bạn sẽ làm được
- Viết câu lệnh if đúng cú pháp và luôn dùng ngoặc nhọn
- Giải thích vì sao điều kiện trong C thực chất là một số nguyên
- Nhận ra bẫy dấu chấm phẩy thừa sau if
- Kể được bài học từ lỗi goto fail
Câu lệnh if là cấu trúc điều khiển đơn giản nhất, nhưng nó có hai cạm bẫy đã từng gây ra một lỗ hổng bảo mật nghiêm trọng trên toàn bộ hệ sinh thái Apple. Bài này giải thích cả hai.
#Cú pháp
if (dieu_kien)
cau_lenh;
if (dieu_kien) {
cau_lenh_1;
cau_lenh_2;
}Nếu điều kiện đúng thì thân if chạy, nếu sai thì bỏ qua. Điều kiện bắt buộc nằm trong ngoặc tròn, đây là quy định cú pháp chứ không phải để làm rõ độ ưu tiên.
#include <stdio.h>
int main(void)
{
int tuoi = 20;
if (tuoi >= 18) {
printf("Bạn đã đủ tuổi\n");
}
if (tuoi >= 18 && tuoi <= 60) {
printf("Trong độ tuổi lao động\n");
}
return 0;
}#Điều kiện là một số
Đây là điều quan trọng nhất cần hiểu về if trong C. Điều kiện không phải một giá trị logic riêng biệt, nó chỉ là một số. Quy tắc đã học ở Bài 4.3: 0 là sai, khác 0 là đúng.
if (0) { } /* không chạy */
if (1) { } /* chạy */
if (-5) { } /* chạy */
if (0.0) { } /* không chạy */
int n = 3;
if (n) { } /* chạy, vì n khác 0 */
if (n - 3) { } /* không chạy, vì biểu thức bằng 0 */Hệ quả là mọi biểu thức trong C đều dùng làm điều kiện được, kể cả phép gán. Đó chính là lý do lỗi if (x = 5) ở Bài 4.2 biên dịch được mà không báo lỗi.
#Bẫy dấu chấm phẩy
Bài 2.1 đã nhắc tới bẫy này. Ở đây ta xem hậu quả cụ thể của nó.
if (x > 0);
{
printf("x dương\n");
}
/* Dấu chấm phẩy là thân của if, và nó là câu lệnh RỖNG.
Khối ngoặc nhọn phía dưới trở thành một khối độc lập,
LUÔN chạy bất kể x là bao nhiêu. */if (x > 0) {
printf("x dương\n");
}Trình biên dịch không báo lỗi vì cả hai dòng đều hợp lệ về cú pháp. Cờ -Wempty-body, nằm trong -Wextra, sẽ cảnh báo trường hợp này. Đây là một lý do nữa để không bao giờ bỏ -Wextra.
#Vì sao luôn dùng ngoặc nhọn
C cho phép bỏ ngoặc nhọn khi thân chỉ có một câu lệnh. Đừng dùng đặc quyền đó. Lý do rõ nhất nằm ở một sự cố có thật.
Ba lý do luôn dùng ngoặc nhọn
- Thêm dòng an toàn. Sau này bạn thêm một câu lệnh nữa vào thân mà quên thêm ngoặc, chương trình sai âm thầm.
- Tránh bẫy else lơ lửng. Xem Bài 5.2.
- Thụt lề không nói dối. Với ngoặc nhọn, cấu trúc thật của mã luôn khớp với cách nó trông trên màn hình.
if (loi)
ghi_log();
/* Ba tháng sau, ai đó thêm một dòng: */
if (loi)
ghi_log();
thoat(); /* LUÔN chạy, kể cả khi không có lỗi */if (loi) {
ghi_log();
}
/* Thêm dòng thì tự nhiên nằm đúng chỗ: */
if (loi) {
ghi_log();
thoat();
}Tự làm thử
- Viết chương trình nhập một số rồi in ra số đó dương, âm hay bằng 0.
- Thêm dấu chấm phẩy sau
if (x > 0), biên dịch với-Wextravà đọc cảnh báo. - Viết lại đoạn mã goto fail cho đúng, dùng ngoặc nhọn, và giải thích vì sao lỗi không thể tái diễn.
- Viết chương trình kiểm tra một số có phải năm nhuận hay không, dùng đúng một câu lệnh
if. - Kiểm chứng quy tắc chân lý: viết
ifvới điều kiện là0,1,-5,0.0,'0'và'\0', in ra nhánh nào chạy.
Trình chấm điểm tự động sẽ được bổ sung ở giai đoạn sau. Hiện tại bạn tự chạy thử trên máy.
Tóm tắt
- Điều kiện của if là một số: 0 là sai, mọi giá trị khác 0 là đúng.
if (x > 0);có thân rỗng, khối phía sau luôn chạy. Bật-Wextrađể bắt lỗi này.- Luôn dùng ngoặc nhọn, kể cả khi thân chỉ có một câu lệnh.
- Lỗi goto fail của Apple năm 2014 là hậu quả trực tiếp của việc bỏ ngoặc nhọn.