歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> 【C語言】關於宏定義中#和##符號的使用和宏定義展開問題

【C語言】關於宏定義中#和##符號的使用和宏定義展開問題

日期:2017/3/1 9:43:19   编辑:Linux編程

有一道經典的C語言問題,關於宏定義中#和##符號的使用和宏定義展開問題

程序如下:

#include <stdio.h>
#define f(a,b) a##b
#define g(a) #a
#define h(a) g(a)

int main()
{
printf("%s\n", h(f(1,2)));
printf("%s\n", g(f(1,2)));
return 0;
}

答案:第一行:12 第二行:f(1,2)

說明:

1、關於符號#和##

兩個符號都只能用於預處理宏擴展。不能在普通的源碼中使用它們,只能在宏定義中使用。

簡單的說,#是把宏參數變為一個字符串,##是把兩個宏參數連接在一起。

關於這兩個符號的具體意義和用法可以參見兩篇文章:

#和##在宏替換中的作用 http://www.linuxidc.com/Linux/2014-06/102921.htm

C/C++ 宏中"#"和"##"的用法 http://www.linuxidc.com/Linux/2014-06/102924.htm

還有GCC幫助文檔上的解釋:

3.4 Stringification

3.5 Concatenation

2、關於宏展開

預處理過程的幾個步驟:

1)字符集轉換(如三聯字符)

2)斷行鏈接/

3)注釋處理,/* comment */,被替換成空格

4)執行預處理命令,如#inlcude、#define、#pragma、#error等

5)轉義字符替換

6)相鄰字符串拼接

7)將預處理記號替換為詞法記號

第4)步即如何展開宏函數的規則:在展開當前宏函數時,如果形參有#或##則不進行宏參數的展開,否則先展開宏參數,再展開當前宏。

宏替換順序英文描述如下:

A parameter in the replacement list, unless preceded by a # or ## preprocessing token or followed by a ## preprocessing token, is replaced by the corresponding argument after all macros contained therein have been expanded.

3、總結

綜合以上,對於這道題來說,第一行h(f(1,2)),由於h(a)非#或者##所以先展開其參數f(1,2),即12,所以變成h(12),然後再宏替換為g(12),再次替換為12。

第二行g(f(1,2)),宏g(a)帶有#,所以裡面的f(1,2)不展開,所以變成f(1,2)

類似的這種問題在《你必須知道的495個C語言問題》中出現過,在121頁的“預處理功能”的問題11.19,有興趣的朋友可以看一看。

C++ Primer Plus 第6版 中文版 清晰有書簽PDF+源代碼 http://www.linuxidc.com/Linux/2014-05/101227.htm

讀C++ Primer 之構造函數陷阱 http://www.linuxidc.com/Linux/2011-08/40176.htm

讀C++ Primer 之智能指針 http://www.linuxidc.com/Linux/2011-08/40177.htm

讀C++ Primer 之句柄類 http://www.linuxidc.com/Linux/2011-08/40175.htm

C++11 獲取系統時間庫函數 time since epoch http://www.linuxidc.com/Linux/2014-03/97446.htm

C++11中正則表達式測試 http://www.linuxidc.com/Linux/2012-08/69086.htm

Copyright © Linux教程網 All Rights Reserved