So sánh vĩ mô if-directive


25

Tại sao #ifđiều kiện trong đoạn mã sau được đáp ứng:

#include <iostream>
#define VALUE foo    

int main() {    
#if VALUE == bar
    std::cout << "WORKS!" << std::endl;
#endif // VALUE
}

Câu trả lời:


26

Các trang trên cppreference.com trạng thái:

Sau khi tất cả mở rộng và đánh giá macro của các biểu thức được xác định và __has_include (kể từ C ++ 17), bất kỳ định danh nào không phải là chữ boolean đều được thay thế bằng số 0 (điều này bao gồm các định danh là từ khóa từ vựng, nhưng không phải là mã thông báo thay thế như và ).

Vì vậy, cả hai foobarđược thay thế bằng 0.


Còn C ++ 98, C ++ 03, C ++ 11 và C ++ 14 thì sao?
kalalaka

1
@kelalaka Tất cả đều giống nhau. Đó là cách đó kể từ C89.
SS Anne

1
@kelalaka Phần "kể từ C ++ 17" chỉ đề cập đến phần "và __has_include". Trước C ++ 17 cũng vậy, chỉ cần bỏ qua phần đó.
BessieThe

15

Trong một #iftuyên bố, bất kỳ định danh nào còn lại sau khi thay thế macro (ngoại trừ truefalse) được thay thế bằng hằng số 0. Vì vậy, chỉ thị của bạn trở thành

#if 0 == 0

cái nào đúng.


Để làm rõ, '#define VALUE foo' định nghĩa biểu tượng 'GIÁ TRỊ' để giải quyết cùng giá trị với biểu tượng 'foo', nhưng biểu tượng 'foo' không có nghĩa, vì vậy nó sẽ được hiểu là 0.
ManicDee

14

Điều này là do cả hai foocũng không barđược đưa ra bất kỳ định nghĩa hoặc giá trị nào - vì vậy chúng giống nhau (nghĩa là được thay thế bằng giá trị "0"). Trình biên dịch sẽ đưa ra cảnh báo về điều này.

Trình MSVCbiên dịch (Visual Studio 2019) đưa ra các thông tin sau:

cảnh báo C4668: 'foo' không được định nghĩa là macro tiền xử lý, thay thế bằng '0' cho '# if / # elif'
cảnh báo C4668: 'bar' không được định nghĩa là macro tiền xử lý, thay thế bằng '0' cho '#if / # elif '

Vì vậy, VALUEđược đưa ra giá trị '0' (mặc định cho foo) và barcũng có '0', do đó, VALUE == barđánh giá thành "TRUE".

Tương tự, clang-clđưa ra như sau:

cảnh báo: 'foo' không được xác định, đánh giá thành 0 [-Wundef]
cảnh báo: 'bar' không được xác định, ước tính thành 0 [-Wundef]


Là cảnh báo bắt buộc hoặc nó là một tính năng của trình biên dịch?
kalalaka

1
@kelalaka Theo hiểu biết tốt nhất của tôi, không có 'cảnh báo' nào của trình biên dịch là bắt buộc! Ngay cả với trình biên dịch MSVCclang-cltrình biên dịch, cảnh báo này có thể bị vô hiệu hóa (cụ thể hoặc bằng cách đặt 'mức' cảnh báo thích hợp).
Adrian Mole

0

Để thực hiện những gì bạn đang theo đuổi, hãy thử điều này:

#include <iostream>
#define DEBUG  

int main() {    
#ifdef DEBUG
    std::cout << "WORKS!" << std::endl;
#endif
}

Trong trường hợp này, bạn có thể tắt các câu lệnh gỡ lỗi bằng cách thay đổi "xác định" thành "undef".

#include <iostream>
#undef DEBUG  

int main() {    
#ifdef DEBUG
    std::cout << "WORKS!" << std::endl;
#endif
}

Bạn có thể thấy rằng trình biên dịch của bạn cho phép bạn xác định DEBUG bên ngoài mã, tại thời điểm đó bạn có thể giảm mã xuống

#include <iostream>

int main() {    
#ifdef DEBUG
    std::cout << "WORKS!" << std::endl;
#endif
}

Và sau đó gọi trình biên dịch với một tùy chọn như -DDEBUG = 0

Kiểm tra chương về Lập trình phòng thủ trong Steve McConnell, "Hoàn thành mã".

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.