GCC擴充套件符( , )

2021-06-22 06:42:59 字數 1463 閱讀 1742

先來說說這兩個擴充套件符的各自用處吧

,「#」是將巨集字串化(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) \  

\  }  open_file(fd1, 1);  

open_file(fd2, 2);  

其展開的等價**如下:

[cpp]  

};  

};  

值得注意的是,##擴充套件符是用來連線兩個標籤,但是這兩個標籤之一不能為空!

但是使用這兩個擴充套件符,有乙個極容易出現錯誤的地方,那就是巨集展開的問題,且看下面這個例子:

[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.

GCC擴充套件特性

遇到了乙個關於零陣列定義的問題,總結如下 零陣列的使用的好處是 它在結構裡不占用空間,但是結構可以通過它訪問結構之外的資料。這也給了它的很大的訪問許可權,因此在通過零陣列訪問之前,一定要檢查訪問範圍的有效性。下面是乙個簡單的例子 include include typedef struct arra...

C 語言的 GCC 擴充套件

gnu 編譯器 gcc 提供了很多 c 語言擴充套件,編譯器會使用該資訊生成更高效的機器 內聯函式 static inline attribute always inline int foo void 避免內聯 attribute noinline int foo void 純函式 attribut...

擴充套件運算子

三個點,主要是用來將陣列幻化為用逗號分隔的引數序列。合併陣列 與解構賦值結合 如果將擴充套件運算子用於陣列賦值,只能放在引數的最後一位,否則會報錯。將字串轉為真正的陣列 可以將類似陣列的物件轉為真正的陣列 map和set結構,generator函式 擴充套件運算子內部呼叫的是資料解構的iterato...