2011-03-28 72 views
10

我想在编写代码C是这样的:使用定义(MACRO)的内部C if语句

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

,但我找不到任何方式Ç要做到这一点,因为定义的(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()预处理程序操作。

+1

的可能重复的[宏取决于宏](http://stackoverflow.com/questions/4927976/macro-dependent-macro) – kennytm 2011-03-28 19:53:29

回答

2

为什么不简单定义ASSERT取决于该宏?使用C条件语句

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

使用固定的值预处理应避免 - 确保编译器应该从优化死代码,但是为什么依靠,当你基本上可以去掉实际的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 

本质上,它使用事实上,当预处理器令牌是而不是定义为ma它会扩大到自己。另一方面,当它被定义为时,它将扩展为空字符串或其定义。除非你的一个宏有其自己的名字作为定义,这个黑客应该工作。

免责声明:使用此信息需自担风险!

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

编辑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 

即使没有优化,海湾合作委员会减少此计划为一个puts()电话。这个程序产生完全相同的汇编输出:

#include <stdio.h> 

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

    return 0; 
} 

因此,你可能不会有任何性能问题,这取决于你的编译器和任何的优化...

+0

不,那是没有好处。我总是想定义ASSERT,但是如果NAME不确定,那么我不想做任何事情。另外,我不想用#ifdef #ifdef – 2011-03-28 19:49:14

+0

@Miklos Maroti将ASSERT的每个用法都括起来:因此NAME的定义不是全局的,而ASSERT是,而且只有在定义了NAME时才需要ASSERT才能工作? – thkala 2011-03-28 19:55:22

+0

我想写这样的代码:ASSERT(UART,var> = 0); ASSERT(SPI,var == 0);因此,如果我定义了UART,那么应该打开所有uart断言,如果我定义了SPI,那么应该打开所有spi断言,并且我不想要预定义的固定数量的子系统,即ASSERT_UART,ASSERT_SPI不是一个好的解决方案。 – 2011-03-28 19:56:40

5

确定的基础上,以前的帖子我有这个想法,这似乎工作:

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

这将检查名称定义,因此它与0扩展为空字符串在它的第一个字符,或者它在CAS未定义e它不是空字符串。这适用于海湾合作委员会,所以可以写

 
if(DEFINED(MACRO)) 
    ... 
+0

请记住,它使用C语句,只会在预编译器中进行扩展。据我所知,C编译器然后意识到,条件的结果是静态的,并消除了未使用的代码... – Johanness 2013-01-01 12:06:29

+1

很酷,但它只适用于空宏...那就是如果你做#define M y,那么DEFINED (M)将返回0(使用gcc 4.5.1测试) – John 2013-05-22 19:22:44

11

通过comex宏扩展为1,如果该参数被定义为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

这应该被接受为答案 – dashesy 2012-05-24 23:00:05

+0

引用的链接不起作用(再)。这是依赖外部链接的问题和答案的一般问题,至少没有引用相关部分。请注意,这是违反网站规则和有效的降低原因的原因。 – Olaf 2016-08-03 13:49:06

+1

@Olaf,链接适用于我。它看起来像G +上的用户个人资料的有效链接:https://plus.google.com/u/ {id}/{id}/posts' – gavv 2016-08-03 14:11:14