如何在作为 ENUM 成员的 DEFINE 上使用预处理器 IF?

How to use preprocessor IF on DEFINE that is an ENUM member?

提问人:Tomer W 提问时间:11/5/2022 最后编辑:Tomer W 更新时间:11/5/2022 访问量:76

问:

我已经为此苦苦挣扎了一段时间,无法让它工作!

我有一个预处理器定义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

这是怎么回事?

如何测试定义是否为枚举值?

C++ 预处理器 C++03

评论

4赞 Colonel Thirty Two 11/5/2022
你不能。预处理器无法知道枚举值。
0赞 Ben Voigt 11/5/2022
@ColonelThirtyTwo 但是预处理器确实知道宏,并且是一个宏LOG_LEVEL
0赞 embeddedstack 11/5/2022
C 和 C++ 是不同的编程语言,请编辑您的标签。
2赞 lorro 11/5/2022
似乎你有 XY 问题。为什么不适合你?if constexpr
2赞 Pete Becker 11/5/2022
预处理令牌定义为 。预处理标记没有定义(因为没有 ),因此它在任何算术表达式中的值都是 0。所以 的值也是 0。而且,由于未定义预处理标记,因此其在任何算术表达式中的值均为 0。事实也是如此。预处理器并不像您希望的那样智能。LOG_LEVELLOG_WARNINGLOG_WARNING#define LOG_WARNING XXXLOG_LEVELLOG_ERRORLOG_LEVEL == LOG_ERRORLOG_LEVEL == LOG_WARNING

答:

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)

但我建议避免为此进行预处理器字符串比较。

如果您确实使用预处理器,我建议根据白名单检查实际值,并使用以停止构建,以防未设置为任何批准的名称。#errorLOG_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++98c++03