【问题标题】:C preprocessor - define macro differently depending on another macroC预处理器 - 根据另一个宏定义不同的宏
【发布时间】:2017-08-25 09:03:14
【问题描述】:

我有一个调试设置,您可以在 makefile 中设置各种调试标志,然后在我们拥有的每个源文件中设置:

#ifdef DEBUG_FLAG
#    define DEBUGGING(...) Something(__VA_ARGS__)
#else
#    define DEBUGGING(...) do {} while(0)
#endif

我想通过让源文件说如下内容来使其更简洁:

#define DEBUGGING(...) DEBUG_HELP( DEBUG_FLAG, Something(__VA_ARGS__) )

其中DEBUG_HELP 在标头中定义,具有相同的最终结果,即使用DEBUGGING 宏将导致Something 被调用,仅当DEBUG_FLAG 被定义为非零时。如果根本没有定义DEBUG_FLAG,那么代码应该仍然可以编译,只是不要调用Something

这可能吗?

到目前为止,我的尝试,在根本没有定义 DEBUG_FLAG 的情况下,我还没有找到不出现编译错误的方法。

【问题讨论】:

  • DEBUG_HELP 的定义方式或位置是否有限制?可以用#ifdef DEBUG_FLAG条件包裹吗?
  • 也许我在这里遗漏了一些东西,但你为什么不能简单地做#if DEBUG_FLAG #define DEBUGGING(...) Something(__VA_ARGS__) #endif

标签: c macros preprocessor


【解决方案1】:

从 Nominal Animal 对类似问题 Test if preprocessor symbol is defined inside macro 的回答中窃取,以下应该有效。如果foo.c 是:

#define STRINGIFY(x) #x

#define DEBUG_HELP(flag, action)                      \
    do {                                              \
        if (strcmp(STRINGIFY(flag), #flag)) &&        \
            strcmp(STRINGIFY(flag), "0")) {           \
            action;                                   \
        }                                             \
    } while (0)

#define DEBUGGING(...) DEBUG_HELP(DEBUG_FLAG, printf(__VA_ARGS__))

DEBUGGING("%d\n", 42);

然后:

$ gcc -E -P foo.c               
do { if (strcmp("DEBUG_FLAG", "DEBUG_FLAG")) && strcmp("DEBUG_FLAG", "0")) { printf("%d\n", 42); } } while (0);
$ gcc -E -P foo.c -DDEBUG_FLAG=0
do { if (strcmp("0", "DEBUG_FLAG")) && strcmp("0", "0")) { printf("%d\n", 42); } } while (0);
$ gcc -E -P foo.c -DDEBUG_FLAG  
do { if (strcmp("1", "DEBUG_FLAG")) && strcmp("1", "0")) { printf("%d\n", 42); } } while (0);
$ gcc -E -P foo.c -DDEBUG_FLAG=bar
do { if (strcmp("bar", "DEBUG_FLAG")) && strcmp("bar", "0")) { printf("%d\n", 42); } } while (0);

所以DEBUG_FLAG 未定义或设置为0if 条件将为假。如果DEBUG_FLAG 是其他任何东西,除了一个例外,条件将为真。一个例外情况是:

#define DEBUG_FLAG DEBUG_FLAG

strcmp 应该在编译时使用 gcc、Clang 和 MSVC 进行评估,尽管我找不到任何保证。作为测试,请参见以下代码:

#include <string.h>
int main(void) {
    if (strcmp("foo", "foo"))
        return 888;
    if (&"foo" != &"foo") // '&' for Clang
        return 999;
    return 777;
}

https://godbolt.org/g/2kVShr 编译。

【讨论】:

    【解决方案2】:

    您可以将条件放在单独的头文件中。

    debug_help.h

    #ifdef DEBUG_FLAG
        #define DEBUG_HELP(...) __VA_ARGS__
    #else
        #define DEBUG_HELP(...) do {} while(0)
    #endif
    

    some_source_module.c

    #include "debug_help.h"
    #define DEBUGGING(...) DEBUG_HELP(puts(__VA_ARGS__))
    
    DEBUGGING("test"); // expands to puts("test"); when DEBUG_FLAG is defined
    

    如果您可以让编译器为每个编译单元自动包含 #include "debug_help.h",则可以省略它。

    【讨论】:

      猜你喜欢
      • 2011-01-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-17
      • 2022-01-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多