预处理器指令#define和其他预处理器指令一样,都是从#开始运行,到第一个换行符结束为止,也就是说预处理器指令的长度仅限于一个逻辑行(C语言中以 ; 作为语句的结束,不以行为单位结束,当一行的内容太长不方便卸载一行时可使用反斜杠"\"作为继续符,分为多行书写) ,在预处理开始前编译器会把多行物理行处理为一行逻辑行。
#define LED_RGBOFF LED_R_OFF;\ /*反斜杠把该定义延续到下一行*/
LED_G_OFF;\
LED_B_OFF
等效于
#define LED_RGBOFF LED_R_OFF;LED_G_OFF; LED_B_OFF
每行#define(逻辑行)都是由三部分构成
#define PBGOFF LED_R_OFF
第一部分 第二部分 第三部分
第一部分是预处理器指令本身#define
第二部分是用户自己定义的名字,也成为宏 ,有些宏代表值(如上例所示),这些宏被称为类对象宏,c语言还有类函数宏会在接下来介绍,宏的名称与变量的命名规则相同。只能使用字符数字和下划线,且首字符不能使数字。
第三部分称为替换列表或替换体 ,预处理找到宏后会用替换体代替宏。
例如:
#include <stdio.h>
#define student_amount 10
#define square_stu student_amount*student_amount
#define pa printf("A is %d.\n",a)
#define zxc "A is %d.\n"
int main()
{ /* 等效于 */
int a = student_amount; /* int a = 10 */
pa; /* printf("A is %d.\n",a) */
a = square_stu; /* a = 10*10 */
printf(zxc,a); /* printf("A is %d.\n",a) */
return 0;
}
运行上述程序后输出如下:
A is 10.
A is 100.
在进行预编译时,预处理器不做计算,不对表达式求值,只进行替换。
在前面提到过在一行的结尾加上反斜杠则可以使该行扩展至下一行如下所示
#define kabuda "yuzhouwudi\
dashuaige" /*反斜杠把该定义延续到下一行*/
注意,第二行要与第一行对齐,如果这样做
#define kabuda "yuzhouwudi\
dashuaige" /*反斜杠把该定义延续到下一行*/
printf(kabuda);
那么输出的内容是
kabuda "yuzhouwudi dashuaige"
从第二行开始到da之间的空格也算是字符串的一部分。
一般而言,预处理器发现程序的宏后,会用宏对应的替换体进行替换,如果替换的字符串中还包含宏,则继续替换这些宏。唯一例外的是双引号中的宏。
如
printf("kabuda");
那么输出的结果是
kabuda
另外在#define中使用参数可以创建外形和作用与函数类似的类函数宏 ,带有参数的宏看上去很像函数,因为这样的宏也使用圆括号。类函数宏定义的圆括号中可以有一个或多个参数,随后这些参数出现在替换体中。
#define square_parameter(x) x*x
看上去和函数调用没有什么不同,其实还是有本质的区别,如下例所示,带有一些陷阱。
#include <stdio.h>
#define square_paramemter(a) a*a
int main()
{
int x = 10;
int z;
z = x;
printf("z = %d\n", z);
z = square_paramemter(x);
printf("z = %d\n", z);
z = square_paramemter(x+2);
printf("z = %d\n", z);
return 0;
}
输出结果是
z = 10
z = 100
z = 22
第三个z为什么不是144,而是22,是因为我们前面提到的。预处理器不做计算,不求值,只替换字符序列,所以为10+2*10+2结果为22。
所以为了避免上例的错误,我们可以在宏定义的时候多加几个括号
#define square_paramemter(a) ((a)*(a))