在C if语句中使用定义的(MACRO)

时间:2011-03-28 19:40:01

标签: gcc c-preprocessor

我想在 C 中编写代码:

if(defined(MACRO))
  ...
else
  ...

但我找不到任何方法在 C 中执行此操作,因为定义的(MACRO)预处理器操作符仅在#if内部工作。有没有办法做到这一点?

我真正想做的是写:

ASSERT(UART, var >= 0);

,其中

#define ASSERT(NAME, TEST) \
  do { \
    if (defined(NAME) && !(TEST)) \
      printf("Assert failed"); \
  } while(0)

因此我可以在定义宏时启用ASSERT检查,如果未定义宏,则不应检查断言。如果你试图这样做,那么你得到:

implicit declaration of function `defined'

这是可以理解的,因为GCC编译器找不到defined()预处理器运算符。

3 个答案:

答案 0 :(得分:11)

如果参数定义为1,则comex的宏扩展为1.否则它将扩展为0:

#define is_set(macro) is_set_(macro)
#define macrotest_1 ,
#define is_set_(value) is_set__(macrotest_##value)
#define is_set__(comma) is_set___(comma 1, 0)
#define is_set___(_, v, ...) v

您可以按如下方式使用它:

if (is_set(MACRO)) {
   /* Do something when MACRO is set */
}

答案 1 :(得分:5)

好的,基于上一篇文章,我得到了这个想法,这似乎有用:

#define DEFINEDX(NAME) ((#NAME)[0] == 0)
#define DEFINED(NAME) DEFINEDX(NAME)

这将检查是否定义了NAME,因此它会扩展为第一个字符为0的空字符串,或者它是未定义的,在这种情况下它不是空字符串。这适用于GCC,所以可以写

if( DEFINED(MACRO) )
  ...

答案 2 :(得分:2)

为什么不根据该宏简单地定义ASSERT

#ifdef MACRO
#define ASSERT(NAME, TEST) \
    do { \
        printf("Assert failed"); \
    } while(0)
#else
#define ASSERT(NAME, TEST) {}
#endif

应该避免在C条件中使用固定的预处理器值 - 确保编译器应该优化死代码,但为什么在基本上删除实际的C代码时依赖它?

编辑:

你可能可以使用一个涉及宏参数字符串化的丑陋技巧:

#include <string.h>
#include <stdio.h>

#define X

#define ERROR_(NAME, TEXT) \
        if (strcmp("", #NAME) == 0) \
                printf("%s\n", TEXT)
#define ERROR(n, t) ERROR_(n, t)

int main() {
    ERROR(X, "Error: X");
    ERROR(Y, "Error: Y");

    return 0;
}

输出:

$ ./test
Error: X

本质上,它使用的事实是,当预处理器令牌定义为宏时,它会扩展为自身。另一方面,当 定义时,它会扩展为空字符串或其定义。除非您的某个宏有自己的名称作为定义,否则此 hack 应该可以正常工作。

免责声明:使用此风险需要您自担风险!

(...因为我肯定使用它!)

编辑2:

上述程序的gcc -O0 -S汇编输出为:

        .file   "test.c"
        .section        .rodata
.LC0:
        .string "Error: X"
        .text
.globl main
        .type   main, @function
main:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        movq    %rsp, %rbp
        .cfi_offset 6, -16
        .cfi_def_cfa_register 6
        movl    $.LC0, %edi
        call    puts
        movl    $0, %eax
        leave
        ret
        .cfi_endproc
.LFE0:
        .size   main, .-main
        .ident  "GCC: (GNU) 4.4.3"
        .section        .note.GNU-stack,"",@progbits

即使没有优化,GCC也会将此程序缩减为单puts()次呼叫。该程序产生完全相同的汇编输出:

#include <stdio.h>

int main() {
    puts("Error: X");

    return 0;
}

因此,您可能不会出现任何性能问题,具体取决于您的编译器和任何优化...