C语言学习笔记_C语言宏定义与预处理
C语言学习笔记_C语言宏定义与预处理
由源码到可执行程序的过程
- 源码;
- 预处理过的.i源文件
- 汇编文件.s
- 目标文件.o
- elf可执行程序
条件编译
// 定义XXX
#define XXX
// 这种方式直接判定XXX是否被定义
#ifdef XXX
#else
#endif
// 这种方式判断条件是否为真
#if (1)
#else
#endif
宏定义
宏定义在编译器的预处理阶段会被直接替换;
替换的过程是递归的,如下:
#define N 10
#define M N
// 相当于int a[10];
int a[M];
当宏定义带参数的时候,擅用括号,避免替换的时候出现歧义,如获取最大值的宏:
#define MAX(a, b) ((a) > (b) ? (a) : (b))
int max(int a, int b) {
return a>b?a:b;
}
int a = 1, b = 2;
int max = MAX(a*3, b);
这里例子可能举得不是很好,但是在某些时候不加括号会使得替换后引起歧义,导致出错;
带参宏和带参函数有如下差别:
- 宏定义原地展开,因此没有调用开销;而函数是跳转执行在返回;
- 宏定义不会检查参数的类型,返回值也不会附带类型,而函数有明确的参数类型和返回值类型;当调用函数时编译器会做参数的静态类型检查;
另外一个例子,利用宏定义得到一年有多少秒:
#define SER_PER_YEAR (365*24*60*60UL)
注意:
在程序中的数字默认为int类型,而秒数正好超过了int的范围;
所以在数字后面加上UL使得数组变成无符号long;
另外一个例子,利用条件宏设置debug
// 定义DEBUG
#define DEBUG
// 使用undef消除对DEBUG的定义
#undef DEBUG
#ifdef DEBUG
#define debug(x) printf(x)
#else
#define debug(x)
#endif
debug("hello world.\n");
通过定义DEBUG,使得debug可以用于打印信息,如果不需要了可以注释DEBUG的定义,或者使用undef,使得消除调试信息更方便。
使用undef时,前面若没有定义过,将会无视此语句;
内联函数
在宏定义中讲到,带参宏和函数的区别是:带参宏开销小但是不做类型检查,函数有调用开销但是会做类型检查;
而内敛函数具有上述两者的优点,其没有调用开销且会做类型检查,只需要在函数前加inline
inline void printInfo() {
printf("hello world.\n");
}