C語言參考手冊閱讀筆記:預先處理指令之#,##,可變參數

來源:互聯網
上載者:User

---------------------------------------------------------------
 3.3.8 將記號轉換為字串 [C語言參考手冊,p38(r54)]
---------------------------------------------------------------
    標準C語言中有一種機制可以將宏參數(擴充之後)轉換為字串型常量。在此之前,編程人員要利用許多C語言前置處理器中的漏洞以不同方式達到相同結果。
    在標準C語言中,宏定義中出現的#記號被當作一元“字串化”運算子,後面為宏正式參數名。宏擴充期間,#和正式參數名換成相應的包含在字串引號當中的實際參數。產生字串時,記號參數表中的每個空白序列換成一個空格符,任何嵌人引號和反斜線前面加上一個反斜線以保留其在字串中的含義。參數開頭和末尾的空白符忽略,因此空參數擴充為空白字串""(即使逗號之間有空白符)。

例:考慮TEST宏的標準c語言定義

#define TEST(a,b) printf(#a "<" #b "=%d/n", (a)<(b))
語句TEST(0,0xFFFF);TEST('/n', 10);展開如下:
printf("0" "<" "0xFFFF" "=%d/n", (0)<(0xFFFF));
printf("'//n'" "<" "10 "=%d/n", ('/n')<(10));

---------------------------------------------------------------
 3.3.9 宏擴充中的記號合并 [C語言參考手冊,p38(r54)]
---------------------------------------------------------------
    標準C語言中合并記號形成新記號時,由宏定義中的合并運算子##控制。重新掃描更多宏之前,宏替換表中任何運算子##中間的兩個記號合并成一個記號。因此必須有這種記號:##不能放在替換表開頭或末尾。如果合并之後得不到有效記號,則結果是未定義的。

例子:
#define TEMP(i) temp ## i
TEMP(1) = TEMP(2 + k) + x;
預先處理之後變成:
temp1 = temp2 + k + x;

    上例中,擴充TEMP()+x時可能出現一個奇妙的情形。宏定義是有效,但##右邊沒有要組合的記號(除非遇到+,但這不是我們所要的)。要解決這個問題,應把正式參數i看成是專為##擴充的特殊的“空”記號。這樣,TEMP()+x擴充的結果將如我們預料的那樣為temp+x。
    不能用記號拼接產生通用字元名。
    和宏參數轉換成字串時一樣(見3.3.8節),編程人員可以利用許多非標準C語言實現中的漏洞獲得這種合并功能。儘管C語言的原始定義明確地把宏體描述成記號序列,而不是字元序列,但許多語言編譯器把宏體當作字元序列一樣擴充和重新掃描。這在編譯器處理備註陳述式時更加明顯,編譯器將備註陳述式完全刪除而不是換成空格,因此一些巧妙編寫的程式就可以利用這個特性。
例:考慮下列例子:
#define INC        ++
#define TAB        internal_table
#define INCTAB    table_of_increments
#define CONC(x,y)    x/**/y
CONC(INC,TAB)

    標準C語言將CONC體解釋為兩個記號x和y,用空格分開(備註陳述式變成空格)。調用CONC(INC,TAB)擴充為兩個記號INC TAB。但有些非標準C語言實現直接刪除備註陳述式,然後重新掃描宏體中的記號,這樣就把CONC(INC,TAB)擴充為一個記號INCTAB;

 -----------------------------------------------
 步驟    標準C語言擴充        可能的非標準擴充
 -----------------------------------------------
 1    CONC(INC,TAB)        CONC(INC,TAB)
 2    INC/**/TAB                  INC/**/TAB
 3    INC TAB                      INCTAB
 4    ++ internal_table      table_of_increments

測試代碼:

#define XVARNAME(i)        x##i
#define PXVARNAME(n)    printf("x"#n" = %d/n",x##n)

int k = 0;
int b = 0;
int XVARNAME(k)=12;
    PXVARNAME(k + 1);                         //xk + 1 = 13
    PXVARNAME(k);                                //xk = 12
    b = XVARNAME(k) + 0;
    printf("b = %d, k =  %d/r/n", b, k);    //b = 12, k = 0
    b = XVARNAME(k + 10) + 0;
    printf("b = %d, k =  %d/r/n", b, k);    //b = 22, k = 0

---------------------------------------------------------------
 3.3.10  宏中的可變參數表 [C語言參考手冊,p38(r54)]
 notice: Visual C++ 直至8.0版才開始支援C99的可變宏定義
---------------------------------------------------------------
#ifdef DEBUG
#define myprintf(...) fprintf(stderr, __VA_ARGS__)
#else
#define myprintf(...) fprintf(__VA_ARGS__)
#endif

特別地:
#define make_em_str(...) #__VA_ARGS__
下列調用
make_em_str(a,b,c,d)
展開成字串
"a,b,c,d"

-------------------------------------------------------------------------------------------------------------------------
題外話:
討厭得益網的積分增加方法,但是,那裡的有些東東確實不錯,如果您願意,幫忙點一下:
http://www.netyi.net
--------------------------------------------------------------------------------------------------------------------------

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.