2017-09-08 27 views
2

我在分析代碼時碰到下面的宏。不可理解的C宏

#define __COMMAND_HANDLER(name, extra ...) int name(struct command_invocation *cmd, ## extra) 

name作爲參數傳遞給__COMMAND_HANDLER功能但沒有此功能的代碼其他地方的定義。定義了cmd參數的類型(command_invocation)。基本上我無法理解這個宏的功能,因爲我找不到函數name的定義。標準C庫中是否定義了某種預定義的函數?如果沒有定義name,這個宏定義是否有意義?

+1

請注意,宏定義不是標準C;它使用的是GNU擴展。如果它是一個標準的宏,那麼在三個點之前會有一個逗號。此外,以雙下劃線(或下劃線和大寫字母)開頭的名稱保留供'執行'使用。你不應該在你自己的代碼中定義這樣的宏。 –

回答

1

德寧preprocession,預處理器將取代__COMMAND_HANDLER(name, extra ...)宏的所有地方,以它的機身採用替代的nameextra...每個OCCURENCES其身體內部到您指定的令牌。

這意味着,無論你的name參數輸入這種情況下,這將是一個函數名,extra...將是第一個(struct command_invocation *cmd)旁的附加參數。

例如,下面的一行:

__COMMAND_HANDLER(foo, int param) { 
    /* definition */ 
} 

後預處理將是:

int foo(struct command_invocation *cmd, int param) { 
    /* definition */ 
} 

一個重要的事情必須要澄清:在##extra之前並命名變量參數(使用extra...代替...)不是標準的一部分,但它們是GNU extensions。逗號後面的##的作用使您不指定變量參數。編譯與海灣合作委員會(與-pedantic標誌)時,它的使用方法如下的例子,你會看到警告信息:在##運算符兩邊

/* The following example will print the following messages: 
* warning: ISO C does not permit named variadic macros [-Wvariadic-macros] 
* warning: ISO C99 requires at least one argument for the "..." in a variadic 
* macro 
*/ 
__COMMAND_HANDLER(bar); 

一般情況下,##是令牌串聯操作,即兩個令牌組合成一個單一的。例如:

#include <stdio.h> 
#define FOO(name, number) void name##number() 

FOO(bar, 1) { puts("I'm first."); } 
FOO(bar, 2) { puts("I'm second."); } 

int main() { 
    bar1(); 
    bar2(); 
    return 0; 
} 
0

這是一個宏,名稱是一個參數。 你使用這樣的:

__COMMAND_HANDLER(hello, char* world) 

在預處理階段,這將改變你的代碼:

int hello(struct command_invocation *cmd, char *world); 

在這種情況下,名稱爲傳遞問候,並額外=字符*世界。 如果你沒有通過任何額外的東西,##會丟棄逗號。

+0

請詳細說明'...'與'##'組合的效果。 – Yunnosch

0

簡而言之:宏創建具有由extra ...指定的參數name和任選的另外的參數指定的名稱的功能。

注意:以雙下劃線開頭的名稱是實現保留的,不應使用。

該宏是可變的。

extra ...的第二個參數提供了一個名稱來代替函數聲明宏中的默認__VA_ARGS__。這是一個GNU擴展

## extra是另一個GNU擴展,它向預處理器指定如果省略了宏__COMMAND_HANDLER的第二個參數,則可以刪除前面的逗號,並且可以在沒有它的情況下調用該函數。

您無法找到name聲明的原因是因爲它是您的宏的一個參數!宏本身正在聲明一個新的函數,其中包含名稱和參數,默認的第一個參數爲struct command_invocation *cmd

下面是一些例子:

呼叫:
__COMMAND_HANDLER(cmd,char * w)
將導致函數聲明:
int cmd(struct command_invocation *cmd,char * w)

而調用:
__COMMAND_HANDLER(cmd2)
將導致函數聲明:
int cmd2(struct command_invocation *cmd)