提问人:Tomer W 提问时间:11/5/2022 最后编辑:Tomer W 更新时间:11/5/2022 访问量:76
如何在作为 ENUM 成员的 DEFINE 上使用预处理器 IF?
How to use preprocessor IF on DEFINE that is an ENUM member?
问:
我已经为此苦苦挣扎了一段时间,无法让它工作!
我有一个预处理器定义LOG_LEVEL它定义了我的程序应该发出哪些日志。
我有很多 LOG 点,因此需要性能,因此,
不使用运行时检查来log_level。
我将我的代码修剪为可以玩的最小有问题的结构(这里)[https://onlinegdb.com/u39ueqNAI]:
#include <iostream>
typedef enum {
LOG_SILENT=0,
LOG_ERROR,
LOG_WARNING,
LOG_INFO,
LOG_DEBUG
} E_LOG_LEVELS;
// this define is set using -DLOG_LEVEL=LOG_WARNING to the compiler.
#define LOG_LEVEL LOG_WARNING
int main() {
std::cout << "Logging Level Value is " << LOG_LEVEL << std::endl; // output 2 (correctly)
#if LOG_LEVEL==LOG_WARNING
std::cout << "Log Level Warning!" << std::endl; // outputs (correctly)
#endif
#if LOG_LEVEL==LOG_ERROR
std::cout << "Log Level Error!" << std::endl; // outputs (Why ??? )
#endif
return 0;
}
主要问题是 #if LOG_LEVEL==LOG_* 始终为 true。
我也试过了,但这返回了 FALSE (uff)。#if LOG_LEVEL==2
这是怎么回事?
如何测试定义是否为枚举值?
答:
4赞
Ben Voigt
11/5/2022
#1
为此,您不需要预处理器。一个正常的
if (LOG_LEVEL <= LOG_WARNING)
当条件仅涉及常量并且构建具有任何优化时,不会创建运行时测试。
现代 C++ 允许您强制编译器在编译时使用 实现条件。即使禁用了优化,也会修剪掉枯枝。if constexpr (...)
最后,如果您坚持使用预处理器,并且可以保证宏将使用符号名称(您永远不会使用 进行构建),则可以g++ -DLOG_LEVEL=2
#define STRINGIFY(x) #x
#define STRINGY2(x) STRINGIFY(x)
#define PP_LOG_LEVEL STRINGY2(LOG_LEVEL)
#define LOG_LEVEL_IS(x) STRINGY2(LOG_LEVEL)==STRINGIFY(x)
然后任一
#if PP_LOG_LEVEL=="LOG_WARNING"
或
#if PP_LOG_LEVEL_IS(LOG_WARNING)
但我建议避免为此进行预处理器字符串比较。
如果您确实使用预处理器,我建议根据白名单检查实际值,并使用以停止构建,以防未设置为任何批准的名称。#error
LOG_LEVEL
评论
0赞
Tomer W
11/5/2022
我正在使用 VxWorks 6.9,它使用带有 C++ std'01 的旧编译器,因此 constexpr 是不可能的。但是你关于优化的观点是有效的,我没有检查实际生成的代码。
2赞
Ben Voigt
11/5/2022
@TomerW:您应该用 OR(没有 2001 C++标准)标记您的问题,以表明编译器的限制。c++98
c++03
评论
LOG_LEVEL
if constexpr
LOG_LEVEL
LOG_WARNING
LOG_WARNING
#define LOG_WARNING XXX
LOG_LEVEL
LOG_ERROR
LOG_LEVEL == LOG_ERROR
LOG_LEVEL == LOG_WARNING