预处理器是在真正的编译开始之前由编译器调用的独立程序。预处理器可以删除注释、包含其他文件以及执行宏(宏macro是一段重复文字的简短描写)替代。预处理器可由语言(如C,PHP要求或以后作为提供额外功能(诸如为FORTRAN提供Ratfor预处理器)的附加软件。
预定义宏
ANSI C定义了一些宏。虽然每一个可以供您使用的编程,预定义宏不应该被直接修改。
符号 | 例子 | 含义 |
---|---|---|
DATE | “Jun 18 2016” | 文件被编译的时间 |
TIME | “15:47:03” | 文件被编译的时间 |
FILE | “test.c” | 进行编译的源文件名 |
LINE | “8” | 文件当前的行号 |
STDC | “1” | 如果编译器遵循ANSI C,其值就为1,否则未定义 |
例子:1
2
3
4
5
6
7
8
9#include <stdio.h>
int main()
{
printf("File :%s\n", __FILE__ );
printf("Date :%s\n", __DATE__ );
printf("Time :%s\n", __TIME__ );
printf("Line :%d\n", __LINE__ );
printf("ANSI :%d\n", __STDC__ );
}
输出:
File :test.c
Date :Jun 18 2016
Time :15:47:03
Line :8
ANSI :1
预处理常量 define:
预处理器指令从#开始,到最后第一个换行符为止。如果在结尾出现反斜杠,则定义会自动延续到下一行。1
2
3
4
5
6
7
8/*define定义一个常量MAX_VALUE*/
#define MAX_VALUE 10
/*define结尾出现反斜杠,定义自动延续到下一行*/
#define PARAGRAPH “This is the first example\
of define "
printf(“max value is %d\n”,MAX_VALUE);
printf(“paragraph is %s\n”,PARAGRAPH);
每个define行有三部分组成。
- 第一部分为#define本身;
- 第二部分为所选择的缩略语,成为宏,宏的名字中不允许有空格,我们约定使用大写表示。
*第三部分为宏替换的文本,成为宏展开。如果没有替换文本,我们成为一个基本宏定义。
宏判断:
如果我们想一些段落代码,只在部分宏有定义的情况下才只用,我们这里会用到宏判断。
格式:1
2
3
4
5#ifdef XXX
...
#else
...
#endif
例:1
2
3
4
5
6
7
8
9
10
11
12#define PROJECT_TEST
int main(void)
{
#ifdef PROJECT_TEST
printf(“marco PROJECT_TEST is defined\n”);
#else
printf(“marco PROJECT_TEST not defined\n”);
#endif
return 0;
}
如果我们在工程中定义了PROJECT_TEST这个宏,则打印第一段,否则打印第二段。
宏函数:
宏函数,即用宏的方式来实现函数。
宏函数末尾不能带分号做结尾。
宏函数中的参数都需要用括号扩起来。
例如:1
2
3
4
5#define SEQUERE(a) a*a
int seq_value;
int a = 4;
seq_value = SEQUERE(a);
printf(“seq_value = %d\n”,seq_value);
输出:16
但是这种写法有个问题,如果我们传入的a为 a+1时,就会发生问题。
1
2
3
4 int seq_value;
int a = 4;
seq_value = SEQUERE(a+1);
printf(“seq_value = %d\n”,seq_value);输出: 9
输出的内容为9,而不是我们期望的25.
我们简化一下这个程序SEQUERE(a) aa
变为a+1a+1
a为4,所以结果为4+1*4+1 = 9.
为了避免这种情况,我们在宏函数中的每个参数都需要用小括号()括起来。
即为#define SEQUERE(a) (a)*(a)