C语言预处理器是个简单的的宏处理器,预处理器用特殊的命令行控制,这些命令行以#开头,不包含预处理器命令的行称为源程序文本行。预处理器通常从源文件中删除所有预处理器命令行,并按预处理器命令指示对源文件进行其它转换,然后,得到的经过预处理的源文本成为有效C语言程序。
下面是常见的预处理器命令:
#define——定义预处理器宏,如果是函数式宏定义,左括号与宏名之间不能有空格,所有参数及整个宏替换最好分别放在圆括号里,参数可以是可变参数表,以...表示,用__VA_ARGS__替换,传人参数包含自赠自减运算符时会带来副作用,还需注意的是宏定义结束处的分隔符。
#undef——取消预处理器宏定义。
#include——插入另一源文件中的文本。
#if——根据常量表达式值有条件地包括一些文本。
#ifdef——根据是否定义宏有条件地包括一些文本。
#ifndef——根据与#define相反的测试有条件地包括一些文本。
#else——上述#if、#ifdef、#ifndef或#elif测试失败时包括一些文本。
#endif——终止条件文本。
#line——提供编译器消息的行号。
#elif——上述#if、#ifdef、#ifndef或#elif测试失败时根据另一常量表达式值包括一些文本。
defined——预处理器函数,在一个名称定义为预处理器宏时为1,否则为0,在#if与#elif中使用。
#运算符——将宏参数换成包含参数值的字符串常量。
##运算符——从两个相邻记号生成一个记号。
#pragma——对编译器指定相关消息,效果同C99增加的_Pragma运算符。#pragma可以单独放在一行,其预处理器记号不随宏扩展,而_Pragma可以放在其它表达式中间,可以通过宏扩展产生。
#error——将编译错误换成指定消息。
标准C语言预处理器要求定义某些对象式宏,每个预定义宏的名称以两个下划线字符开头和结尾,这些预定义宏不能被取消定义(#undef)或由编程人员重新定义。
下面是常见的预定义宏——
__LINE__:当前源程序行的行号,表示为十进制整形常量。
__FILE__:当前源文件名,表示为字符串型常量。
__DATE__:转换的日历日期,表示为"MM
dd yyyy"形式的字符串型常量,MM是由asctime产生的。
__TIME__:转换的时间,表示为"hh:mm:ss"形式的字符串型常量,是由asctime产生的。
__STDC__:编译器为ISO兼容实现时为十进制整形常量1。
__STDC_VERSION__:如果实现符合C89增补1,则这个宏的值为199409L;如果实现符合C99,则这个宏的值为199901L;否则数值是未定义。
__STDC_HOSTED__:(C99)实现为宿主实现时为1,实现为独立实现时为0。
__STDC_IEC_559__:(C99)浮点数实现符合IEC
60559标准时定义为1,否则数值是未定义。
__STDC_IEC_559_COMPLEX__:(C99)复数运算实现符合IEC
60559标准时定义为1,否则数值是未定义。
__STDC_ISO_10646__:(C99)定义为长整型常量,yyyymmL表示wchar_t值符合ISO
10646标准及其指定年月的修订补充,否则数值未定义。
另外,实现还经常定义其它宏用于传递环境消息,如进行程序编译工作的计算机类型。具体定义哪些宏是由实现决定的,但UNIX实现习惯上预定义unix。与内置宏不同的是,这些宏可以取消定义。标准C语言要求特定实现的宏名以下划线开头,加上大写字母或另一个下划线(unix宏不符合这个要求)。
C99定义了几个标准杂注,FF_CONTRACT、FENV_ACCESS和CX_LIMITED_RANGE,它们取一个参数作为开关:ON、OFF、DEFAULT。
预定义标识符尽管不是关键字,但C99中引入了预定义标识符的概念,并定义了一个预定义标识符:__func__。与预定义宏不同的是,预定义标识符可以采用正常的标识符作用域规则,和关键字一样,预定义标识符不能由编程人员定义。
C++使用C89预处理器,因此C语言与C++之间差别不大。宏__cplusplus是C++实现中预定义的,可以在C和C++环境中的源文件中使用。这个名称不符合预定义宏的标准C语言拼写规则,但与现有C++实现兼容。在标准C语言中,它的值为199711L之类的版本号。__STDC__是否在C++环境中定义取决于实现。标准C语言与C++有一定差别,因此不知道是否要定义__STDC__。