1.对于由#define定义的类函数宏,应使用足够数量的圆括号,如
#define SQUARE(X) ((X)*(X))
此举是为了避免替换时由于运算优先级而出现的不可预料的错误
另外,为了保证类函数宏正确运算,尽量不要使用自增(自减)运算进行宏替换
2.宏与函数比较
1)宏产生内联代码,即在代码中出现宏的所有地方都进行替换。而整个程序中只有一份函数拷贝。因此从空间上讲函数优于宏。另一方面,函数的调用时间开销大于宏,因此在时间上宏优于函数。
2)在程序中只使用一次的宏对运行时间不会产生明显改善。而在嵌套循环中使用宏更有助于加速程序运行。
3.头文件中通常包含
1)#define所定义的常量和类函数宏
2)函数声明
3)外部变量声明(extern)
4)结构模板定义(struct)
5)类型定义(typedef)
4.#undef:取消定义一个给定的#define,如
#define SIZE 400
则指令:
#undef LIMIT
会取消该指令
即使开始没有定义LIMIT,取消LIMIT的定义也是合法的
如果想使用一个特定名字,又不确定前面是否已经使用了该名字,为安全起见,就可以取消该名字的定义
5.#ifdef MAVIS
#include "horse.h" //若已用#define定义了MAVIS,则执行这里的命令
#define STABLES 5
#else
#include "cow.h" //若没有用#define定义MAVIS,则执行这里的命令
#define STABLES 15
#endif //判断结束
#ifdef的应用:一是可以实现条件编译,将测试代码放在#ifdef和#endif之间,通过操作对应的#define来实现测试代码的加入和删除;二是使用#ifdef选择适用于不同C实现的大块代码
6.#ifndef用于判断后面的标识符是否为未定义的。#ifndef通常用来定义此前未定义的常量。
一般地,当某文件包含几个头文件,而且每个头文件都可能定义了相同的宏时,使用#ifndef可以防止对该宏的重复定义
7.对于用角括号包含的头文件,gcc
首先查找-I
选项指定的目录,然后查找系统的头文件目录(通常是/usr/include
,在我的系统上还包括/usr/lib/gcc/i486-linux-gnu/4.3.2/include
);而对于用引号包含的头文件,gcc
首先查找包含头文件的.c
文件所在的目录,然后查找-I
选项指定的目录,然后查找系统的头文件目录。
8.重复包含头文件有以下问题:
1)使预处理的速度变慢了,要处理很多本来不需要处理的头文件
2)如果有foo.h
包含bar.h
,bar.h
又包含foo.h
的情况,预处理器就陷入死循环了(其实编译器都会规定一个包含层数的上限)
3)头文件里有些代码不允许重复出现,虽然变量和函数允许多次声明(只要不是多次定义就行),但头文件里有些代码是不允许多次出现的,比如typedef
类型定义和结构体Tag定义等,在一个程序文件中只允许出现一次。