1.__FILE__进行编译的源文件
2.__LINE__文件当前的行号
3.__DATE__文件被编译的日期
4.__TIME文件被编译的时间
5.__STDC__如果编译器遵循ANSIC,其值为1,否则未定义
基本语法:#define 名字 内容 eg.define M 1
经#define定义的常量时不经过任何计算,直接打印 eg #define M 1+1则M = 1 + 1(不是2)
注意:在用#define定义时后面不要加 ; 否则可能导致错误
#define机制规定允许把参数替换到文本中,这种实现通常称为"宏"或者"定义宏"
eg.#define (x) (x)*(x)
宏的参数中如果有操作符,因为运算符有优先级的问题,可能导致运算顺序错误,因此在宏的书写时,最好给参数带上括号
当宏参数在宏定义中出现超过一次时,如果参数带有副作用,使用宏时就可能存在危险
eg.
#define MAX(x,y) ((x) > (y) ? (x) : (y))
int main()
{
int a,b;
a = 3;
b = 5;
int m = MAX(a++,b++);
}
此时由于a++,b++具有副作用(修改了a和b本身的值),会导致输出结果m = 6,此时a = 4,b = 7
1.在调用宏时,首先检查参数中是否有#define定义的符号,如果有就首先替换它
2.替换文本随后被插入到程序中原本的文本的位置,即参数名被值替换
3.再次对结果文件扫描,看是否包含由#define定义的符号,如果有,重复操作
注意:1.宏参数和#define定义中可以出现其他#define的符号,但是宏不能递归
2.当预处理器搜索#define定义的符号时,字符串常量 的内容不会被搜索
宏通常用于较简单的运算
宏的程序规模和速度较好,效率更高,同时,宏对参数类型没有要求
宏的劣势:
1.每次宏的使用,一份宏的代码就会被插入到程序中,除非宏比较短,否则会大大增加程序的长度
2.宏无法调试
3.由于宏对类型不做要求,所以不够严谨
4.宏可能存在运算符优先级的问题,容易导致程序出错
宏和函数的语法相似,为了方便区分宏和函数,通常将宏的名字全部大写,函数的名字不全部大写
#运算符将宏的一个参数转换为字符串字面量,可以理解成字符串化,时参数不转换成对应的值
##运算符可以把它两边的符号合成一个符号,这样的连接必须产生一个合法的标识符,否则结果未定义
eg.使用宏定义求最大值的函数
#define GET_MAX(type)\
type type##_max(type x,type y)\
{\
return (x > y ? x : y);\
}
在这段宏定义中,##会将type和_max拼接在一起得到函数名
后面就可以正常调用函数了
eg.
int m = int_max(1,2);
double n = double_max(1.5,2.3);
这条指令用于移除一个宏定义
在编译程序时可以使用条件编译指令经语句编译或放弃
条件编译指令:
1.
#if 常量表达式
...
#elif
...
#else
...
#endif
它的使用类似与 if 的用法
注意:条件编译指令在预处理阶段完成,所以不能用变量表示(预处理阶段变量未生成)
2.判断是否被定义
#ifdef (或者#ifndef,表示如果没定义)
...
#endif
也可以用#if define ... (#if !define)代替
使用#include "..."
查找策略:先在源文件所在目录查找,如果找不到,编译器在像查找库函数头文件一样在标准位置查找头文件
使用#include <...>
查找策略:直接在标准库中查找
当工程较大时,可能存在头文件的多次包含,而头文件的多次包含会导致代码量大增,为了防止头文件的重复包含,可以使用#pragma once