2009-11-20 26 views
2

我試圖做一些概念上類似於這個,但似乎無法得到它的工作(錯誤顯示在最後)任何想法?C編程:預處理器,宏作爲標記

#include <stdio.h> 

int main(int argc , char const *argv[]) 
{ 
    int abc_def_ghi = 42; 
    #define SUFFIX ghi 
    #define VAR(prefix) prefix##_def_##SUFFIX 
    printf("%d\n" , VAR(abc)); 
    return 0; 
} 

// untitled:8: error: ‘abc_def_SUFFIX’ undeclared (first use in this function) 
+0

'const argv'?我第一次看到這樣的事情!這個想法看起來很不錯,但我不確定我是否喜歡它:它使'main'不符合要求,並且阻止我做我從未做過的事情;) – pmg 2009-11-20 01:43:43

+2

這不是不符合要求。 'argv'可以被聲明爲等同於'char * argv []'(C99 5.1.2.2.1)的東西,並且除了允許'main()'允許做什麼之外,在那裏添加'const'並不會改變任何東西它(沒有演員)。請記住,指向非const的指針可以轉換爲指向常量沒有問題的指針 - 直至這些指針的值將相等(6.3.2.3/2)。 – 2009-11-20 08:42:55

+0

對,謝謝邁克爾。反過來(刪除'const')會導致它不符合規定。我開始喜歡它! – pmg 2009-11-20 09:43:02

回答

10

你只需要額外的間接:

#include <stdio.h> 

int main(int argc , char const *argv[]) 
{ 
    int abc_def_ghi = 42; 
    #define SUFFIX ghi 
    #define VAR3(prefix, suffix) prefix##_def_##suffix 
    #define VAR2(prefix, suffix) VAR3(prefix, suffix) 
    #define VAR(prefix) VAR2(prefix, SUFFIX) 
    printf("%d\n" , VAR(abc)); 
    return 0; 
} 

即使它看起來多餘的,事實並非如此。

+0

你能解釋一下爲什麼嗎? – liori 2009-11-20 01:13:20

+0

對於我來說,嘗試理解'6.10.3.3 ##運算符'的標準有點太晚了,但它解釋了爲什麼在某處。 (pdf @ http://www.open-std.org/JTC1/sc22/wg14/www/docs/n1401.pdf) – pmg 2009-11-20 01:33:16

+1

因爲宏的替換列表本身並不會在其參數被替換前進行宏替換並應用#和##運算符。所以在提問者的代碼中,'def _ ## SUFFIX'被替換爲'def_SUFFIX',然後纔有機會用'ghi'替換'SUFFIX'。在caf的代碼中,當VAR2中'suffix'被'SUFFIX'替代時,參數首先被宏擴展(6.10.3.1/1)。結果是'VAR3(abc,ghi)',它產生'abc_def_ghi'。請注意,'VAR3(abc,SUFFIX)'仍然會給出'abc_def_SUFFIX',因爲參數##後面沒有擴展(也是6.10.2.1/1)。 – 2009-11-20 01:45:55

7

正確使用字符串化(#)或令牌粘貼(##)預處理操作符的常用術語是使用第二級間接尋址。 (What are the applications of the ## preprocessor operator and gotchas to consider?)。

#define STRINGIFY2(x) #x 
#define STRINGIFY(x) STRINGIFY2(x) 

#define PASTE2(a, b) a##b 
#define PASTE(a, b) PASTE2(a, b) 

然後:

int main(int argc , char const *argv[]) 
{ 
    int abc_def_ghi = 42; 
    #define SUFFIX ghi 
    #define VAR(prefix) PASTE(prefix, PASTE(_def_, SUFFIX)) 
    printf("%d\n" , VAR(abc)); 
    return 0; 
} 

應該給你你要尋找的結果。

基本上,發生的事情是###運算符的處理髮生在宏替換之前。然後再發生一輪宏觀替代。所以如果你希望宏和這些操作一起使用,你必須使用第一級來替換 - 否則字符串化或粘貼首先發生,而宏不再是宏 - 它們是第一輪串化/粘貼產生。

更直接地說 - 宏的第一級允許宏參數被替換,然後宏替換的第二級進行stringify/token-pasting操作。

+0

哇,謝謝你,STRINGIFY也解決了我遇到的另一個問題。 – 2009-11-21 11:54:56

0

這適用於足夠的間接性。而另一個答案是充足的充足,我想提供的代碼,這個塊作爲演示:

#define SUFFIX ghi 

#define VAR1(prefix) prefix##_def_##SUFFIX 
VAR1(abc) 

#define VAR2_(prefix, sfx) prefix##_def_##sfx 
#define VAR2(prefix) VAR2_(prefix,SUFFIX) 
VAR2(abc) 

#define VAR3_(prefix, sfx) prefix##_def_##sfx 
#define VAR3x(prefix,sfx) VAR3_(prefix,sfx) 
#define VAR3(prefix) VAR3x(prefix,SUFFIX) 
VAR3(abc) 

保存這是一個文本文件,x.c,只有預處理它。

gcc -E x.c 

觀察和思考。我自己並不完全理解它。只需花費兩個小時試圖使用stringify工作來獲得宏。有趣的是,有時需要雙重間接。

+0

我得到 abc_def_SUFFIX abc_def_SUFFIX abc_def_ghi 基於史蒂夫的解釋,這聽起來像它與宏替換的順序做。 – 2010-01-17 18:30:18