先來說說這兩個擴展符的各自用處吧,“#”是將宏字符串化(Stringification),“##”是將##左右兩邊的標簽組合在一起(token pasting or token concatenation),下面從兩個簡單例子著手: [cpp] #define SSVAR(X,Y) const char X[]=#Y SSVAR(InternetGatewayDevice, InternetGatewayDevice.); 上面這個例子實質是借用了#擴展符去實現名為InternetGatewayDevice的字符數組初始化,其等價代碼(可以通過gcc –E展開獲得)如下: [cpp] const char InternetGatewayDevice[]="InternetGatewayDevice."; 下面這個例子比較常見,用於打開不同的路徑。 [cpp] #define DEV_FILE_NAME "/dev/test_kft" #define OPEN_FILE(fd, n) \ { \ fd = open(DEV_FILE_NAME ##n, 0); \ if (fd < 0) \ { \ printf("Open device error/n"); \ return 0; \ } \ } OPEN_FILE(fd1, 1); OPEN_FILE(fd2, 2); 其展開的等價代碼如下: [cpp] { fd1 = open(DEV_FILE_NAME1, 0); if (fd1 < 0) { printf("Open device error/n"); return 0; } }; { fd2 = open(DEV_FILE_NAME2, 0); if (fd2 < 0) { printf("Open device error/n"); return 0; } }; 值得注意的是,##擴展符是用來連接兩個標簽,但是這兩個標簽之一不能為空! 但是使用這兩個擴展符,有一個極容易出現錯誤的地方,那就是宏展開的問題,且看下面這個例子: [cpp] #define xstr(s) str(s) #define str(s) #s #define foo 4 str(foo); //->”foo” xstr(foo); //->xstr(4)->str(4)->”4” 為什麼str(foo)與xstr(foo)展開之後會出現完全不同的結果呢?此處就涉及到宏展開的規則問題:在宏預掃描((macro prescan)階段,宏參數首先會被替換,替換之後,再經過下次的掃描完成最後宏的展開(macro expand),OK,說到此,似乎str(foo)在預掃描階段應該會變成str(4),但是GCC在宏預處理階段,特意加上了一條排外規則,那就是若宏參數被用於字符串化或者與其它標簽連接,則不會被替代!結果也就可想而知了。下面是摘抄的一段預處理規則: Macro arguments are completely macro-expanded before they are substituted into a macro body, unless they are stringified or pasted with other tokens. After substitution, the en-tire macrobody, including the substituted arguments, is scanned again for macros to be expanded.