预编译发生在编译之前
会检查.C文件中的所有#开始的语句。
#define.
其实是对.c文件的一系列replace,例如
例1.
a.h
#define WIDTH 768
#define HEIGHT 1260
#define Area‘ = WIDTH * HEIGHT
预编译检查的时候会去除# 并进行替换
#define Area‘ = WIDTH * HEIGHT
define Area‘ = 768* 1260
例2
a.h
#define Max(a,b) ((a)>(b))?(a):(b)
a.c
#include "a.h
int main(int argc, char *argv[])
{
int a = 10,b=20;
return max(a,b);
}
预编译后
变成
int main(int argc, char *argv[])
{
int a = 10,b=20;
return ((a)>(b))?(a):(b);
}
#define宏的优势,快速,不需要函数的堆栈操作
劣势,调用者容易出现错误
例如
int main(int argc, char *argv[])
{
int a = 10,b=20;
return max(a++,b++);
}
会导致a++调用了2次
宏#include
编译器在编译的时候会检查#include.
把#include中对应的文件内容,合并到.c文件中
例如
a.c
#include <stdio.h>
int main()
{
printf("hello world");
}
编译器在编译阶段会将printf文件的定义加载到.c文件中
a.c文件在编译后会成为.o文件,.o文件包括printf的定义,编译器会将stdio.h文件中的内容全部加入到.o文件中,部分好的编译器会将.c文件中未使用到的函数定义删除,在我们的例子中会只包括如printf函数的定义.
某些编译器例如GCC,如果a.c文件中没有#include ,如下代码
int main()
{
printf("hello world");
}
编译器会产生一个warning,没有定义printf函数,但是编译会继续进行,并假设printf函数原型为 int printf(char *) 编译器会把函数都假设返回类型为int 。
在编译器连接时,会查找系统库,由于printf在系统库中有定义,所以程序可以正常运行
注: #include <stdio.h> 查找系统库; #include ”a.h“ 查找程序目录
为了避免开发人员容易出现的错误,头文件循环,如在
a.h
#include "b.h"
b.h
#include "a.h"
编译器采用
#ifndef _A_H
#def _A_H
#endif
这样确保在编译后,只保存一份a.h和b.h,不会出现死循环