2011-02-24 87 views
15

是否可以在預處理過程中連接字符串?使用預處理器的字符串串聯

我發現這個例子

​​

但是它並沒有爲我工作 - 打印出「你好」當我用gcc -std=c99

UPD這個例子貌似現在的工作。但是,它是c預處理器的一個正常特性嗎?

回答

36

級聯相鄰串litterals的不預處理器的功能,它的核心是語言(C和C++)的功能。你可以這樣寫:

printf("Hello " 
     " world\n"); 
10

gcc online docs

的 '##' 的預處理操作者進行標記粘貼。當一個宏展開時,每個'##'運算符兩邊的兩個令牌被合併成一個單獨的令牌,然後替換宏擴展中的'##'和兩個原始令牌。

考慮一個解釋命名命令的C程序。有可能需要在命令表,或許聲明爲結構數組如下:

struct command 
{ 
    char *name; 
    void (*function) (void); 
}; 

struct command commands[] = 
{ 
    { "quit", quit_command }, 
    { "help", help_command }, 
    ... 
}; 

這將是清潔不必須給每個命令的名字兩次,一次在字符串常量,一次在功能名稱。以命令的名稱作爲參數的宏可以使這不必要。可以使用字符串化創建字符串常量,並通過將參數與_command連接來創建函數名稱。下面是它是如何做:

#define COMMAND(NAME) { #NAME, NAME ## _command } 

struct command commands[] = 
{ 
    COMMAND (quit), 
    COMMAND (help), 
    ... 
}; 
17

你確實可以連接預處理器中的標記,但要小心,因爲它很棘手。關鍵是##運算符。如果你在你的代碼的頂部拋出這樣的:

#define myexample(x,y,z) int example_##x##_##y##_##z## = x##y##z 

話,基本上,這是什麼呢,是在預處理過程中,它會採取任何調用該宏,如下列:

myexample(1,2,3); 

,它會從字面上變成

int example_1_2_3 = 123; 

這可以讓你一噸的靈活性,同時編碼,如果你正確地使用它,但它並不完全適用你如何嘗試使用它。用一點按摩,你可以讓它工作。爲你的榜樣

一個可能的解決方案可能是:

#define H "Hello " 
#define W "World!" 
#define concat_and_print(a, b) cout << a << b << endl 

,然後像做

concat_and_print(H,W); 
+0

這是一個C++標準或只是一個gcc功能? – bibi 2016-12-09 07:38:39

+0

在你的例子中,連接是在運行時完成的,而不是由預處理器完成。 – 2017-06-13 15:19:13

4

我只是想我要補充一點,引用源,爲什麼這個問題的解答。

C99標準§5.1.1.2定義了C代碼的轉換階段。第6條規定:

  • 相鄰字符串文字令牌是級聯。
  • 類似地,在C++標準(ISO 14882)§2.1定義翻譯的相位。這裏子部分6陳述:

    6將相鄰的普通字符串文字標記連接在一起。相鄰的寬字符串文字標記是連接的。

    這就是爲什麼你可以將它們彼此相鄰的簡單連接字符串:

    printf("string"" one\n"); 
    
    >> ./a.out 
    >> string one 
    

    問題的預處理部分的#define預處理指令,它不會取代簡單地使用從標識符(H)到字符串("Hello ")。