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

Mik*_*oti 11 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()预处理器运算符.

vit*_*aut 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
Run Code Online (Sandbox Code Playgroud)

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

if (is_set(MACRO)) {
   /* Do something when MACRO is set */
}
Run Code Online (Sandbox Code Playgroud)

  • 引用的链接不起作用(不再)。这是问题和答案依赖于外部链接而不至少引用相关部分的普遍问题。请注意,这违反了站点规则和有效的反对理由。 (2认同)

Mik*_*oti 5

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

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

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

if( DEFINED(MACRO) )
  ...

  • 很酷,但是它仅适用于空宏...也就是说,如果您执行#define M y,则DEFINED(M)将返回0(使用gcc 4.5.1测试) (2认同)

thk*_*ala 2

为什么不简单地ASSERT根据该宏进行不同的定义?

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

应避免在 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;
}
Run Code Online (Sandbox Code Playgroud)

这输出:

$ ./test
Error: X
Run Code Online (Sandbox Code Playgroud)

本质上,它利用了这样一个事实:当预处理器标记未定义宏时,它会扩展为自身。另一方面,当它定义时,它会扩展为空字符串或其定义。除非您的宏之一有自己的名称作为定义,否则此技巧应该有效。

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

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

编辑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
Run Code Online (Sandbox Code Playgroud)

即使没有进行优化,GCC 也会将该程序简化为一次puts()调用。该程序产生完全相同的汇编输出:

#include <stdio.h>

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

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

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