C预处理器:在程序执行之前查看程序。根据程序中的预处理器指令,预处理器把符号缩写替换成其表示的内容。
预处理指令示例:
#define、#include、#ifdef、#else、#endif、#ifndef、#if、#elif、#line、#error、#pragma
ANSI和后来的标准都允许 # 前面有空格或者制表符,而且还允许在 # 和指令的其余部分之间有空格。
目录
#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 ,但是实际上是 23
X = 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 ## n
XNAME(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
省略符号只能代替最后的宏参数!!!!
最后,宏名中不允许出现空格!!!在嵌套循环中使用宏定义的函数有助于提高效率,单词循环看不出来效果。