L15 :编译过程
预处理
- 处理注释,以空格代替
- 将所有#define删除,并且展开所有的宏定义
- 处理 #if #ifdef等
- 处理#include,展开被包含的文件
- 保留编译器需要使用的#pragma指令
预处理命令:
gcc -E file.c -o hello.i
编译
语法分析,语义分析,产生汇编代码
gcc -S file.c -o hello.s
链接
- 静态链接
在编译期完成 - 动态链接
在运行期完成
L16 :宏定义与使用分析
特点:强大但是容易出错
#define DIM(array) (sizeof(array)/sizeof(*array))
//获得数组的元素个数
宏表达式与函数的对比:
- 宏表达式只在预编译期被处理,编译器不知道宏表达式的存在
- 宏表达式用“实参”完全替代形参,不进行任何运算
- 宏表达式没有任何的“调用”开销
- 宏表达式中不能出现递归定义
宏定义的作用域?
在一个函数中定义的一个宏 能否在另一个函数中调用 -》可以
如果想要确保一个函数中定义的宏只能在一个函数中被调用,
可以用 #undef来取消这个宏的定义
#include <stdio.h>
int f1(int a, int b)
{
#define _MIN_(a,b) ((a)<(b) ? a : b)
return _MIN_(a, b);
//#undef _MIN_ //如果执行这句后,该程序会出错
}
int f2(int a, int b, int c)
{
return _MIN_(_MIN_(a,b), c);
}
int main()
{
printf("%d\n", f1(2, 1));
printf("%d\n", f2(5, 3, 2));
return 0;
}
强大的内置宏:
利用内置宏实现日志宏
#include <stdio.h>
#include <time.h>
#define LOG(s) do{ \
time_t t; \
struct tm* ti ; \
time(&t); \
ti = localtime(&t); \
printf("%s[%s :%s] %s\n",asctime(ti),__FILE__,__LINE__,s); \
} while(0)
void f()
{
LOG("ENTER f()...");
LOG("EXIT f()...");
}
int main()
{
LOG("ENTER main ...");
f();
LOG("ENTER main ...");
return 0;
}