2011-03-28 69 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