1. #
是字符串化操作符。它的作用是將宏參數轉換成字符串
2.?##
是標記粘貼操作符。它的作用是將兩個標記連接起來形成一個新的標記
#define TEST1(a) #a
#define TEST2(a) b##a/***********************************************************/
舉例:TEST1(hello) 會被替換為 "hello" 字符串TEST2(hello)會被替換為 bhello, 編譯過程中會將bhello當作一個變量
/***********************************************************/
字符串拼接
#define HELLO_WORLD "Hello, " "World!"/***********************************************************/
在HELLO_WORLD中,"Hello, " "World!" 會被連接為 "Hello, World!"HELLO_WORLD 會被替換為 "Hello, World!" 字符串
/***********************************************************/
利用#將宏參數轉換成字符串的特性可以完成字符串的拼接:
#defien HELLO(a) "hello"#a/***********************************************************/
舉例:
HELLO(bye)會被替換為 "hellobye" 字符串HELLO(bye) 被轉換為 "hello""bye" 再轉換為 "hellobye"/***********************************************************/
重要事項
1. 在C或C++中的宏定義中,#運算符(被稱為“字符串化”)只能用于宏參數。這意味著#必須直接跟在參數名稱后面,不能有任何東西介于#和參數名稱之間。換句話說,你不能在#和參數名之間添加任何非空白的字符。
錯誤案例:
#define STRING(a) nihao##a
#define TOSTRING(a) #STRING(a)/*********************************************/這個案例似乎想將nihao與參數a進行拼接并轉換為字符串
但是#與參數之間不能存在其他字符,因此#操作符在此處其實是失效的
執行TOSTRING(a)等價于執行了STRING(a)
TOSTRING(a) 會被替換為 nihaoa, 編譯過程中會將nihaoa當作一個變量。因為#操作符的無效/*********************************************/
2. ##符號兩側的空格會被忽略
#define CONCAT1(a,b) a##b#define CONCAT2(a,b) a ## b/****************************************/CONCAT1(a,b) 與 CONCAT2(a,b) 都會被替換為ab變量/****************************************/
3.?##
運算符還有一個特殊的作用,就是當它跟在一個逗號后面,并且其后面繼續跟隨如##__VA_ARGS__
的類型參數為空時,預處理器就會消除這個逗號
_VA_ARGS__
?是C語言預處理器定義的一個指示符,它代表了可變參數的列表。它主要用于宏的定義中,當你需要定義一個接收可變數量參數的宏時。
#define FOO(fmt, ...) printf(fmt, ##__VA_ARGS__ )/*****************************************************/上述宏如果被傳遞一個參數,例如 FOO( "Hello, world!" ),
則__VA_ARGS__為空,此時##會去掉前面的逗號,從而避免了語法錯誤。/******************************************************/
#__VA_ARGS__將會把__VA_ARGS__轉化為字符串。
#define DEBUG(...) ##__VA_ARGS__/*********************************************/DEBUG(ni, hao, a) 會被替換為 "ni, hao, a" 字符串/**********************************************/