预处理器执行宏替换、条件编译以及包含指定的文件。
#include指令:用于在编译期间把置顶文件的内容包含进当前文件中;
#define指令:用任意字符序列替换一个标记;
1、文件包含
#include指令是一个将所有声明放在一起的好方法,它保证所有的源文件都具有相同的定义与变量(函数)声明。如果某个包含文件的内容发生了变化,那么所以依赖于该包含文件的源文件都必须重新编译。
#include "file name"
#include <file name>
#include 记号序列
在源文件中,上面行将被替换为由文件名指定的文件内容。
如果文件名用引号引起来,则在源文件所在位置查找该文件;如果在该位置没有找到文件或如果文件名是尖括号括起来,则将根据相应的规则查找该文件,这个规则同具体实现有关。
2、宏替换
#define 标识符 记号序列
#define 标识符(标识符表) 记号序列
#undef 标识符
预处理器把该标识符后续出现的各个实例用给定的记号序列替换。
第二次用#define指令定义同一标识符是错误的,除非第二次定义中的标记序列与第一次相同。
通常情况下,#define指令占一行,但也可以把一个较长的宏定义分成若干行,这时需要在待续的行尾加上一个反斜杠\。
替换只对记号进行,对括在引号中的字符串不起作用。
#define max(A, B) ((A) > (B) ? (A) : (B))
如果在替换文本中,参数名以#作为前缀则结果将被扩展为由实际参数替换该参数的带引号的字符串。
#define DPRINT(expr) printf(#expr " = %g\n", expr)
DPRINT(x/y) => printf("x/y = %g\n", x/y)
预处理运算符##为宏扩展提供一种连接实际参数的手段。如果替换文本中的参数与##相邻,则该参数将被实际参数替换,##与前后的空白符将被删除,并对替换后的结果进行重新扫描。
#define PASTE(front, back) front##back
PASTE(fight, ing) => fighting
3、条件包含
用于条件语句可以对预处理本身进行控制。
#if语句对其中的常量整形表达式进行求值,若该表达式的值不等于0,则包含其后的各行,直到遇到#endif、#elif或#else语句为止。
#if !defined(HDR)
#define HDR
...
#endif
#ifndef _CALU_H
#define _CALU_H
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
extern int add(int a, int b);
extern int sub(int a, int b);
extern int mul(int a, int b);
extern int div(int a, int b);
#endif
int add(int a, int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
int mul(int a, int b)
{
return a * b;
}
int div(int a, int b)
{
if (b != 0)
{
return a / b;
}
return 0;
}
#include "calu.h"
#define TEST_NUM 10
#define TEST_ADD
int main()
{
int i = 0;
int a = 3;
int b = 7;
int val = 0;
#if defined(TEST_ADD)
val = add(a, b);
#elif defined(TEST_MUL)
val = mul(a, b);
#else
val = sub(a, b);
val = div(a, b);
#endif
val = MIN(a, b);
val = MAX(a, b);
for (i = 0; i < TEST_NUM; i++) {
val = (val, b);
}
return 0;
}
# 1 "main.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "main.c"
# 1 "calu.h" 1
extern int add(int a, int b);
extern int sub(int a, int b);
extern int mul(int a, int b);
extern int div(int a, int b);
# 2 "main.c" 2
int main()
{
int i = 0;
int a = 3;
int b = 7;
int val = 0;
val = add(a, b);
val = ((a) < (b) ? (a) : (b));
val = ((a) > (b) ? (a) : (b));
for (i = 0; i < 10; i++) {
val = (val, b);
}
return 0;
}
通过:gcc -E main.c -o main.i
可以看到预处理后的.i文件(包括头文件展开、宏替换及条件编译)。