C
C 语法

#define directive

替换文本宏

预处理器支持文本宏替换和类似功能的文本宏替换。

句法

#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指令定义的标识符作为一个宏,即它们指示编译器替换替换列表标识符的所有连续出现,其可以额外地任选地进行处理。如果标识符已经被定义为任何类型的宏,那么该程序是格式不正确的,除非定义相同。

类似于对象的宏

类似于对象的宏将每个定义的标识符替换为替换列表。#define指令的版本(1)的行为完全如此。

函数式的宏

类似功能的宏将替换列表中的每个出现的已定义标识符替换为另外的一些参数,然后替换替换列表中任何参数的相应出现。

函数式宏调用的语法类似于函数调用的语法:宏名称的每个实例后跟一个(作为下一个预处理标记引入由替换列表替换的标记序列)序列由匹配)令牌终止,跳过中间匹配的左右括号对。

参数的数量必须与宏定义(参数)中参数的数量相同或程序不合格。如果标识符不是功能符号,也就是说本身没有括号,它根本不会被替换。

#define指令的版本(2)定义了一个简单的函数式宏。

#define指令的版本(3)定义了一个具有可变数量参数的函数式宏。可以使用__VA_ARGS__标识符访问附加参数,然后使用标识符来替换标识符,然后使用标识符替换它们。

#define指令的版本(4)定义了一个类似函数的宏,其中包含可变数量的参数,但没有常规参数。只能使用__VA_ARGS__标识符访问参数,然后使用标识符替换标识符,并将标识符替换。

注意:如果类似函数的宏的参数包含未被左右括号(如macro(array[x = y, x + 1]))的匹配对保护的逗号,则逗号将被解释为宏参数分隔符,导致由于参数计数不匹配导致的编译失败。

# and ## operators

在函数式宏中,#替换列表中的标识符之前的运算符通过参数替换运行标识符,并将结果封装在引号中,从而有效地创建字符串文字。另外,预处理器会添加反斜杠以避免嵌入的字符串文字(如果有的话)引用,并在必要时将字符串中的反斜杠加倍。所有前导空白和尾随空白都被删除,并且文本中间的任何空白序列(但不在嵌入的字符串文字内)被折叠为单个空格。这个操作被称为“串化”。如果字符串化的结果不是有效的字符串,则行为是未定义的。

当#在__VA_ARGS__之前出现时,整个展开的__VA_ARGS__用引号引起来:#define showlist(...)puts(#__ VA_ARGS__)showlist(); //展开为puts(“”)showlist(1,“x”,int); //展开为puts(“1,\”x \“,int”)(自C99以来)

##在替换列表中的任何两个连续标识符之间的运算符运行两个标识符上的参数替换,然后连接结果。这个操作被称为“连接”或“令牌粘贴”。只有形成一个有效令牌的令牌可以被粘贴:形成一个更长的标识符的标识符,形成一个数字的数字,或运算符,+=形成一个+=。评论不能通过粘贴来创建,/并且*因为在考虑宏替换之前从文本中删除评论。如果连接的结果不是有效的标记,则行为是未定义的。

注意:有些编译器提供了一个允许##出现在逗号之后和__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)

\_\_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): 52 double(21): 42 34 million

参考

  • C11标准(ISO / IEC 9899:2011):