C++中的预处理

一.预定义符号

1.__FILE__进行编译的源文件

2.__LINE__文件当前的行号

3.__DATE__文件被编译的日期

4.__TIME文件被编译的时间

5.__STDC__如果编译器遵循ANSIC,其值为1,否则未定义

二.#define

基本语法:#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);

七.#undef

这条指令用于移除一个宏定义

八. 条件编译

在编译程序时可以使用条件编译指令经语句编译或放弃

条件编译指令:

1.

#if 常量表达式

...

#elif

...

#else

...

#endif

它的使用类似与 if 的用法

注意:条件编译指令在预处理阶段完成,所以不能用变量表示(预处理阶段变量未生成)

2.判断是否被定义

#ifdef  (或者#ifndef,表示如果没定义)

...

#endif

也可以用#if define ... (#if !define)代替

九.头文件包含

1.本地文件的包含

使用#include "..."

查找策略:先在源文件所在目录查找,如果找不到,编译器在像查找库函数头文件一样在标准位置查找头文件

2.库文件的包含

使用#include <...>

查找策略:直接在标准库中查找

3.嵌套文件包含

当工程较大时,可能存在头文件的多次包含,而头文件的多次包含会导致代码量大增,为了防止头文件的重复包含,可以使用#pragma once

你可能感兴趣的:(c++,开发语言)