?
? ????? PHP ??? ???? ??? ?? ??
預處理器支持文本宏替換和類似功能的文本宏替換。
#define identifier replacement-list(optional) | (1) | |
---|---|---|
#define identifier( parameters ) replacement-list | (2) | |
#define identifier( parameters, ... ) replacement-list | (3) | (since C99) |
#define identifier( ... ) replacement-list | (4) | (since C99) |
#undef identifier | (5) |
#define
指令#define
指令定義的標識符作為一個宏,即它們指示編譯器替換替換列表標識符的所有連續(xù)出現,其可以額外地任選地進行處理。如果標識符已經被定義為任何類型的宏,那么該程序是格式不正確的,除非定義相同。
類似于對象的宏將每個定義的標識符替換為替換列表。#define
指令的版本(1)的行為完全如此。
類似功能的宏將替換列表中的每個出現的已定義標識符替換為另外的一些參數,然后替換替換列表中任何參數的相應出現。
函數式宏調用的語法類似于函數調用的語法:宏名稱的每個實例后跟一個(作為下一個預處理標記引入由替換列表替換的標記序列)序列由匹配)令牌終止,跳過中間匹配的左右括號對。
參數的數量必須與宏定義(參數)中參數的數量相同或程序不合格。如果標識符不是功能符號,也就是說本身沒有括號,它根本不會被替換。
#define
指令的版本(2)定義了一個簡單的函數式宏。
#define
指令的版本(3)定義了一個具有可變數量參數的函數式宏??梢允褂?code>__VA_ARGS__標識符訪問附加參數,然后使用標識符來替換標識符,然后使用標識符替換它們。
#define
指令的版本(4)定義了一個類似函數的宏,其中包含可變數量的參數,但沒有常規(guī)參數。只能使用__VA_ARGS__
標識符訪問參數,然后使用標識符替換標識符,并將標識符替換。
注意:如果類似函數的宏的參數包含未被左右括號(如macro(array[x = y, x + 1])
)的匹配對保護的逗號,則逗號將被解釋為宏參數分隔符,導致由于參數計數不匹配導致的編譯失敗。
#
and ##
operators在函數式宏中,#
替換列表中的標識符之前的運算符通過參數替換運行標識符,并將結果封裝在引號中,從而有效地創(chuàng)建字符串文字。另外,預處理器會添加反斜杠以避免嵌入的字符串文字(如果有的話)引用,并在必要時將字符串中的反斜杠加倍。所有前導空白和尾隨空白都被刪除,并且文本中間的任何空白序列(但不在嵌入的字符串文字內)被折疊為單個空格。這個操作被稱為“串化”。如果字符串化的結果不是有效的字符串,則行為是未定義的。
當#在__VA_ARGS__之前出現時,整個展開的__VA_ARGS__用引號引起來:#define showlist(...)puts(#__ VA_ARGS__)showlist(); //展開為puts(“”)showlist(1,“x”,int); //展開為puts(“1,\”x \“,int”) | (自C99以來) |
---|
##
在替換列表中的任何兩個連續(xù)標識符之間的運算符運行兩個標識符上的參數替換,然后連接結果。這個操作被稱為“連接”或“令牌粘貼”。只有形成一個有效令牌的令牌可以被粘貼:形成一個更長的標識符的標識符,形成一個數字的數字,或運算符,+
并=
形成一個+=
。評論不能通過粘貼來創(chuàng)建,/
并且*
因為在考慮宏替換之前從文本中刪除評論。如果連接的結果不是有效的標記,則行為是未定義的。
注意:有些編譯器提供了一個允許##出現在逗號之后和__VA_ARGS__之前的擴展,在這種情況下,當__VA_ARGS__非空時,##什么也不做,但當__VA_ARGS__為空時刪除逗號:這使得可以定義宏等fprintf (stderr, format, ##__VA_ARGS__)
。
#undef
directive#undef
指令取消定義標識符,即它通過#define
指令取消標識符的先前定義。如果標識符沒有關聯的宏,則該指令被忽略。
任何翻譯單元中都預先定義了以下宏名稱:
__STDC__ | expands to the integer constant 1. This macro is intended to indicate a conforming implementation (macro constant) |
---|---|
__STDC_VERSION__ (C95) | expands to an integer constant of type long whose value increases with each version of the C standard: 199409L (C95) 199901L (C99) 201112L (C11) (macro constant) |
__STDC_HOSTED__ (C99) | expands to the integer constant 1 if the implementation is hosted (runs under an OS), 0 if freestanding (runs without an OS) (macro constant) |
__FILE__ | expands to the name of the current file, as a character string literal, can be changed by the #line directive (macro constant) |
__LINE__ | expands to the source file line number, an integer constant, can be changed by the #line directive (macro constant) |
__DATE__ | expands to the date of translation, a character string literal of the form "Mmm dd yyyy". The name of the month is as if generated by asctime and the first character of "dd" is a space if the day of the month is less than 10 (macro constant) |
__TIME__ | expands to the time of translation, a character string literal of the form "hh:mm:ss", as in the time generated by asctime() (macro constant) |
199409L
(C95)
199901L
(C99)
201112L
(C11)
(macro constant)
\_\_STDC\_HOSTED\_\_
(C99)
1
如果實施托管(在 OS 下運行),0
則 擴展為整數常量,如果是獨立的(無 OS 的情況下運行)
(macro constant) __FILE__
擴展為當前文件的名稱,作為字符串文字,可以通過#line 指令進行更改
(macro constant) __LINE__
展開為源文件行號,一個整數常量,可以通過#line 指令進行更改
(macro constant) __DATE__
擴展到翻譯日期,形式為 “Mmm dd yyyy” 的字符串文字。月份的名稱如同生成的一樣,如果asctime
月份的日期小于10,則“dd”的第一個字符是空格
(macro constant) __TIME__
擴展到翻譯時,形式為 “hh:mm:ss” 形式的字符串文字,如在 asctime()
(macro constant)
以下附加宏名稱可能由實現預定義:
__STDC_ISO_10646__ (C99) | expands to an integer constant of the form yyyymmL, if wchar_t uses Unicode, the date indicates the latest revision of Unicode supported (macro constant) |
---|---|
__STDC_IEC_559__ (C99) | expands to 1 if IEC 60559 is supported (macro constant) |
__STDC_IEC_559_COMPLEX__ (C99) | expands to 1 if IEC 60559 complex arithmetic is supported (macro constant) |
__STDC_UTF_16__ (C11) | expands to 1 if char16_t use UTF-16 encoding (macro constant) |
__STDC_UTF_32__ (C11) | expands to 1 if char32_t use UTF-32 encoding (macro constant) |
__STDC_MB_MIGHT_NEQ_WC__ (C99) | expands to 1 if wide character encoding of the basic character set may not equal their narrow encoding, such as on EBCDIC-based systems that use Unicode for wchar_t (macro constant) |
__STDC_ANALYZABLE__ (C11) | expands to 1 if analyzability is supported (macro constant) |
__STDC_LIB_EXT1__ (C11) | expands to an integer constant 201112L if bounds-checking interfaces are supported (macro constant) |
__STDC_NO_ATOMICS__ (C11) | expands to 1 if atomic types and atomic operations library are not supported (macro constant) |
__STDC_NO_COMPLEX__ (C11) | expands to 1 if complex types and complex math library are not supported (macro constant) |
__STDC_NO_THREADS__ (C11) | expands to 1 if multithreading is not supported (macro constant) |
__STDC_NO_VLA__ (C11) | expands to 1 if variable-length arrays are not supported (macro constant) |
這些宏的值(除了__FILE__
和__LINE__
)在整個翻譯單元中保持不變。嘗試重新定義或取消定義這些宏會導致未定義的行為。
預定義變量__func__(詳見函數定義)不是預處理器宏,即使它有時與__FILE__和__LINE__一起使用,例如通過 assert。 | (自C99以來) |
---|
#include <stdio.h> //make function factory and use it#define FUNCTION(name, a) int fun_##name(int x) { return (a)*x;} FUNCTION(quadruple, 4)FUNCTION(double, 2) #undef FUNCTION #define FUNCTION 34#define OUTPUT(a) puts( #a ) int main(void){ printf("quadruple(13): %d\n", fun_quadruple(13) ); printf("double(21): %d\n", fun_double(21) ); printf("%d\n", FUNCTION); OUTPUT(million); //note the lack of quotes}
輸出:
quadruple(13): 52double(21): 4234million
C11標準(ISO / IEC 9899:2011):
6.10.3宏替換(p:166-173)
6.10.8預定義的宏名稱(p:175-176)
C99標準(ISO / IEC 9899:1999):
6.10.3宏替換(p:151-158)
6.10.8預定義的宏名稱(p:160-161)
C89 / C90 標準(ISO / IEC 9899:1990):
3.8.3宏替換
3.8.8預定義的宏名稱