C预处理器:在程序执行之前查看程序。根据程序中的预处理器指令,预处理器把符号缩写替换成其表示的内容。
预处理指令示例:
#define、#include、#ifdef、#else、#endif、#ifndef、#if、#elif、#line、#error、#pragma
ANSI和后来的标准都允许 # 前面有空格或者制表符,而且还允许在 # 和指令的其余部分之间有空格。
目录
#define
记号问题
类函数宏
用宏参数创建字符串:#运算符
预处理器黏合剂:##运算符
变参宏:...和__VA_ARGS__
#define
程序示例:
以下定义都是被允许的!
#include <stdio.h>#define TWO 2#define OW "Consistency is the last refuge of the unimagina\tive. -Oscar Wilde"//反斜杠表示切换到下一行#define FOUR = TWO*TWO#define PX printf("X is %d.\n",x)#define FMT "X is %d.\n"int main(void){ int x = TWO;PX;x = FOUR;printf(FMT,x);printf("%s\n",OW);//这里输出的是代表的字符串!printf("TWO:OW\n"); //这里输出的是:TWO:OW,而不是其代表的字符串和数组!}
拿出一个逻辑行当例子说明:
#define TWO 2
#define是预处理器指令,TWO是选定的缩写,也成为宏。2称为替换列表或替换体。
有些宏代表值,称为类对象宏(object-like macro),还有类函数宏(function-like macro)
在宏定义中,还可以包含其他宏。
记号问题
把宏的替换体看做是记号(token)型字符串,而不是字符型字符串。
#define FOUR 2*2
只有一个记号:2*2序列
#define SIX 2 * 3
这个宏定义有三个记号:2、*、3。
假设编译器解释为字符型字符串,将用2 * 3替换 SIX 。即额外的空格是替换体的一部分。
编译器解释为记号型字符串,则用3个的记号2 * 3(分别由单个空格分隔)来替换 SIX 。
解释为字符型字符串:把空格视为替换体的一部分。解释为记号型字符串:把空格视为替换体中各记号的分隔符。
类函数宏
在 #define 中使用参数可以创建外形和作用与函数类似的类函数宏。参数称为宏参数。
例子:
#define SQUIRE(x) x*x#define SUM(x,y) x+y//调用sum = SUM(5,7);squire = SQUIRE(9);
但是,函数宏只是替换并不是真正的函数!
//列如SQUIRE(2+7)//理想中应该是 81 ,但是实际上是 23X = 100/SQUIRE(2)//理想中应该是 25 ,但是实际上是 100
为什么出现这种状况?实际上的计算过程:
SQUIRE(2+7) = 2+7*2+7 = 23
X =100/SQUIRE(2) = 100/2*2 = 100
编程时应注意
#define SQUIRE(x) ((x)*(x))
用宏参数创建字符串:#运算符
引入例子:
#define PSQR(X) printf("The squire of X is %d.\n",((x)*(x)));//使用宏:PSQR(9);//输出The squire of X is 81.\n
此时 "" 中的 X 被视作普通文本,而不是可替换的符号。
字符串化(stringizing)
#define PSQR(X) printf("The squire of " #X " is %d.\n",((X)*(X)));int main(void){int y = 5;PSQR(y);PSQR(2 + 4);return 0;}
此时的输出为:
The squire of y is 25.
The squire of 2 + 4 is 36.
预处理器黏合剂:##运算符
与 # 运算符类似, ## 运算符可用于 类函数宏 的替换部分。而且, ## 还可以用于对象宏的替换部分。 ## 运算符把两个记号组成为一个记号。
such as:
#define XNAME(n) x ## nXNAME(4) //被编译器解释为x4
## 作为黏合剂的使用:
#define XNAME(n) x ## n#define PRINT(n) printf("X" #n " = %d\n",x ## n);int main(void){int XNAME(1) = 14; //解释为 int x1 = 14;int XNAME(2) = 20;int x3 = 30;PRINT(1); //解释为 printf("x1 = %d\n",x1);PRINT(2);PRINT(3);return 0;}
运行结果有:
x1 = 14
x2 = 20
x3 = 30
体会一下其中的含义吧 ~
变参宏:...和__VA_ARGS__
这个还是需要多考虑一下的!!
这个以前没注意过,读别人代码才发现有这么个东西,我真是沙雕了!
一些函数支持数量可变的参数。如printf() 。
用户可自定义带可变参数的函数,stdvar.h 头文件中提供了工具。
通过把宏参数列表中的最后的参数写成省略号来实现这一功能。这样,预定义宏__VA_ARGS__可用在替换部分中,表明省略号代表什么
#define PR(...) printf(__VA_ARGS__);
程序示例:
#include <stdio.h>#include <math.h>#define PR(X,...) printf("Message " #X ": "__VA_ARGS__)int main(void){double x = 48;double y; //y没定义是乱数y = sqrt(x);PR(1,"x = %g\n",x);//printf("Message 1:x = %g\n",x);PR(2,"x= %.2f, y = %.4f\n",x,y);return 0;}
输出:
Message 1: x = 48
Message 2: x = 48.00, y = 6.9282
省略符号只能代替最后的宏参数!!!!
最后,宏名中不允许出现空格!!!在嵌套循环中使用宏定义的函数有助于提高效率,单词循环看不出来效果。