[英]What does the c precompiler do with macros defined as (void)0
我有一些基於編譯器標志定義的宏。 我正在嘗試決定是否要將宏定義為(void)0或將其定義為未定義並導致編譯時錯誤。
即
#ifdef DEBUG
#define PRINTF(...) printf(__VA_ARGS__)
#else
#define PRINTF(...) (void)0
#endif
int main(void) {
...
PRINTF("something");
...
}
與
#ifdef DEBUG
#define PRINTF(...) printf(__VA_ARGS__)
#endif
int main(void) {
...
#ifdef DEBUG
PRINTF("something");
#endif
...
}
我不確定我喜歡哪種技術。 一方面用#ifdef包裝每個PRINTF語句都很難看。 另一方面,如果我已經調用了一個在上下文中不起作用的函數,那么在編譯時就知道了。
我認為決定因素是(void)0宏是否會影響可執行文件的大小。
編譯代碼時,(void)0會發生什么? 如果PRINTF定義為(void)0,那是否意味着可執行文件將包含某種(void)0指令或是否會被完全忽略?
(void) 0;
是一個沒有副作用的表達式語句。 任何理智的實現都會優化這個語句(實現可以用這樣的語句做什么?)。
如果定義了NDEBUG
則將(void) 0
作為宏定義得到C標准的認可,因為它出現在(C11)7.2p1中,用於assert
宏定義:
#define assert(ignore) ((void)0)
注意定義:
#define PRINTF(...) (void)0
代替
#define PRINTF(...)
有一個優勢。 在第一種情況下,您有一個表達式(就像一個不返回值的函數),因此它可用於例如逗號表達式或條件表達式中。
例如:
// Comma expression
printf("test"), PRINTF("Hi Dennis");
// Conditional expression
test-expr ? perror("Hello") : PRINTF("world");
這兩個表達式語句僅對前PRINTF
定義有效(帶(void) 0
)。
它將被完全忽略,您可以通過查看匯編輸出( gcc -S
將生成file.s,asm輸出)來確認這一點,使用和不使用(void)0行進行比較並看到它完全相同。
一個中等體面的編譯器將優化掉死(不可達)代碼,因此您可以:
#ifdef DEBUG
#define PRINTF(...) if (1) { printf(__VA_ARGS__) ; }
#else
#define PRINTF(...) if (0) { printf(__VA_ARGS__) ; }
#endif
它具有允許編譯器檢查調試代碼的巨大優勢,無論您是否正在使用/未啟用DEBUG
- 這樣可以降低在您的背面留下痛苦牙齒痕跡的風險。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.