C

C 知识量:16 - 74 - 317

16.1 #define><

编译器的工作- 16.1.1 -

在对程序代码进行预处理之前,首先需要让编译器来做一些工作:

1、首先,编译器把源代码中出现的字符映射到源字符集。该过程处理多字节字符和三字符序列。

2、编译器定位每个反斜杠后面跟着换行符的实例,并删除它们。“换行符”的意思是通过按下Enter键在源代码文件中换行所生成的字符,而不是指符号表征\n。例如对于:

printf("That's wond\
        erful!\n");

转换成一个逻辑行:

printf("That's wonderful\n!");

由于预处理表达式的长度必须是一个逻辑行,所以这一步为预处理器做好了准备工作。一个逻辑行可以是多个物理行。

3、编译器把文本划分成预处理记号序列、空白序列和注释序列(记号是由空格、制表符或换行符分隔的项)。编译器将用一个空格字符替换每一条注释,例如:

int/* 这看起来并不像一个空格*/fox;

被处理为:

int fox;

C实现还可以用一个空格替换所有的空白字符序列(不包括换行符)。

#define简介- 16.1.2 -

#define预处理器指令和其他预处理器指令一样,以#号作为一行的开始,到后面的第1个换行符为止。也就是说,指令的长度仅限于一行。

#define可以出现在源文件的任何地方,其定义从指令出现的地方到该文件末尾有效。

在语法上,每行#define(逻辑行)都由3部分组成:

  • 第1部分是#define指令本身。

  • 第2部分是选定的缩写,也称为宏。有些宏代表值,这些宏被称为类对象宏。注意宏的名称中不允许有空格,而且必须遵循C变量的命名规则:只能使用字符、数字和下划线(_)字符,而且首字符不能是数字。

  • 第3部分(指令行的其余部分)称为替换列表或替换体。一旦预处理器在程序中找到宏的示实例后,就会用替换体代替该宏。从宏变成最终替换文本的过程称为宏展开。

define.png

示例1:

#define TWO 2
...
int x = TWO;

宏展开后TWO会替换成2:

int x = 2;

示例2:

#define HELLO "Hello!I love th
\
e world. - Bill" /* 反斜杠把该定义延续到下一行,注意,该行要与第1行左对齐。 */
...
printf("%s\n", OW);

宏展开后,printf()函数将变为:

printf("%s\n", "Hello!I love the world. - Bill");

示例3:

#define TWO 2
#define FOUR  TWO*TWO
...
x = FOUR;

宏展开后,FOUR经过了两次替换:

x = TWO*TWO; //第一次替换
x = 2*2;     //第二次替换

第二次替换后,宏展开到此处为止。由于编译器在编译期对所有的常量表达式(只包含常量的表达式)求值,所以预处理器不会进行实际的乘法运算,这一过程在编译时进行。预处理器不做计算,不对表达式求值,它只进行替换。

示例4:

#define PX printf("X is %d.\n", x)
...
PX;

PX会直接替换成printf()函数:

printf("X is %d.\n", x);

此外,需要特别注意的是:双引号中的宏不会被替换。例如:

printf("TWO: OW");

打印的将是:TWO: OW,预处理器不会对TWO或OW进行替换。

记号- 16.1.3 -

在使用宏进行替换时,可以把宏的替换体看成是记号型字符串。记号型字符串是相对于字符型字符串来说的。可以将记号视为宏定义替换体中单独的“词”,它们之间用空格分隔。例如:

#define SIX 2*3

以上代码中有一个记号,即:2*3。如果在2和3之间加入空格就变为:

#define SIX 2 * 3

此时,记号变为3个,分别是2、*、3。当替换体中有多个空格时,字符型字符串和记号型字符串的处理方式不同。如果预处理器把含有空格的替换体解释为字符型字符串,空格会被视为替换体的一部分;如果解释为记号型字符串,空格会被视为替换体中各记号的分隔符。

需要了解的是,由于编译器理解C语言的规则,所以不要求代码中用空格来分隔记号,替换体中是否使用空格对于代码的正确执行通常没有影响。

重定义常量- 16.1.4 -

如果先把一个宏(例如:LIMIT)定义为10,稍后在该文件中又把它定义为20。这个过程称为重定义常量。通常,在ANSI标准中,只有新定义和旧定义完全相同才允许重定义。

如果需要重定义宏,使用#undef指令。需要知道的是,如果确实需要重定义常量,使用const关键字和作用域规则更容易些。