如何在C++预处理指令#if中判断宏定义为枚举成员?
宏定义日志级别与枚举值预编译判断问题
我通过宏定义LOG_LEVEL控制程序日志输出级别,为保证性能不使用运行时检查,但遇到了预编译判断异常的问题:所有#if LOG_LEVEL==LOG_*的判断始终为真,用#if LOG_LEVEL==2判断结果却为假。精简后的可复现代码如下:
#include <iostream> typedef enum { LOG_SILENT=0, LOG_ERROR, LOG_WARNING, LOG_INFO, LOG_DEBUG } E_LOG_LEVELS; // 编译时通过-DLOG_LEVEL=LOG_WARNING设置 #define LOG_LEVEL LOG_WARNING int main() { std::cout << "Logging Level Value is " << LOG_LEVEL << std::endl; // 正确输出2 #if LOG_LEVEL==LOG_WARNING std::cout << "Log Level Warning!" << std::endl; // 正确输出 #endif #if LOG_LEVEL==LOG_ERROR std::cout << "Log Level Error!" << std::endl; // 意外输出,为什么? #endif return 0; }
问题原因
预处理器在编译阶段之前运行,此时C++的枚举类型还未被编译器解析,LOG_WARNING、LOG_ERROR这类枚举标识符对预处理器来说是未定义的宏,预处理器会将所有未定义的宏视为0。
- 当执行
#if LOG_LEVEL==LOG_ERROR时,LOG_LEVEL被定义为LOG_WARNING,而LOG_WARNING和LOG_ERROR都被预处理器当作0,因此0==0成立,判断为真。 - 当执行
#if LOG_LEVEL==2时,LOG_LEVEL是未被预处理器识别的LOG_WARNING,被当作0,0==2不成立,因此判断为假。
解决方法
方案一:用宏定义替代枚举
直接将日志级别定义为宏,让预处理器能直接识别数值:
#define LOG_SILENT 0 #define LOG_ERROR 1 #define LOG_WARNING 2 #define LOG_INFO 3 #define LOG_DEBUG 4 // 编译时可通过-DLOG_LEVEL=LOG_WARNING或-DLOG_LEVEL=2设置 #define LOG_LEVEL LOG_WARNING
此时预编译判断#if LOG_LEVEL==LOG_WARNING或#if LOG_LEVEL>=LOG_INFO都能正常工作。
方案二:宏与枚举同步定义
如果需要保留枚举类型,用宏来统一定义枚举的数值,让预处理器能识别这些值:
// 用宏定义数值,预处理器可识别 #define LOG_SILENT_VAL 0 #define LOG_ERROR_VAL 1 #define LOG_WARNING_VAL 2 #define LOG_INFO_VAL 3 #define LOG_DEBUG_VAL 4 typedef enum { LOG_SILENT = LOG_SILENT_VAL, LOG_ERROR = LOG_ERROR_VAL, LOG_WARNING = LOG_WARNING_VAL, LOG_INFO = LOG_INFO_VAL, LOG_DEBUG = LOG_DEBUG_VAL } E_LOG_LEVELS; // 编译时通过-DLOG_LEVEL=LOG_WARNING_VAL设置 #define LOG_LEVEL LOG_WARNING_VAL
这种方式既保留了枚举的类型安全,又能让预编译阶段正常判断日志级别。
内容的提问来源于stack exchange,提问作者Tomer W
相关产品推荐
相关产品推荐

