C/C++头文件,宏,内联函数,条件编译

来源:互联网 发布:淘宝女装卫衣 编辑:程序博客网 时间:2024/06/07 19:46

0、头文件在预处理阶段被展开,整个替换进源代码
I、#include两种方式
< >默认到系统预定义的位置查找头文件“ ”在双引号里面的路径(默认路径是当前目录下)查找头文件,如果没找到,再去系统预定义的位置查找。简单来说,自定义的头文件只能用“ ”双引号 ,而库里面的头文件用 “”和< >都可以;
II、如何防止头文件被重复包含:
头文件被重复包含,编译时由于函数或者其他一些东西重定义就会报错;报错出在 阶段
防止头文件被重复包含主要有两种方法:
1、#pragma once 设置编译器:设定编译器的状态或者是指示编译器完成一些特定的动作
还有一个 玩意 #pragma pack(n) 设置默认对齐数 ,

2、条件编译
#ifndef _SOMEFILE_H
#define _SOMEFILE_H
//要写得头文件
#endif
#ifndef的方式依赖于宏名字不能冲突,这不光可以保证同一个文件不会被包含多次,也能保证内容完全相同的两个文件不会被不小心同时包含。当然,缺点就是如果不同头文件的宏名不小心“撞车”,可能就会导致头文件明明存在,编译器却硬说找不到声明的状况。
#pragma once则由编译器提供保证:同一个文件不会被编译多次。注意这里所说的“同一个文件”是指物理上的一个文件,而不是指内容相同的两个文件。带来的好处是,你不必再费劲想个宏名了,当然也就不会出现宏名碰撞引发的奇怪问题。对应的缺点就是如果某个头文件有多份拷贝,本方法不能保证他们不被重复包含。当然,相比宏名碰撞引发的“找不到声明”的问题,重复包含更容易被发现并修正。
方式一 可以避免名字冲突,方式二由语言支持所以移植性好,


III 宏:宏的作用域值是全局范围,不被命名空间和函数等作用域约束 宏用于条件编译很重要,
#define <宏名>(<参数表>) <宏体>(宏定义的后面不加 分号,加了分号就会将分号替换进去 )
宏定义的本质,将一个标识符符定义为一个字符串,源代码中的该标识符均以指定的字符串来代替;
代替的过程叫做宏替换发生在 预处理阶段;
使用#define定义的标识符不是变量,它只用作宏替换,因此不占有内存。
如果某一个标识符被定义为宏名后,在取消该宏定义之前,不允许重新对它进行宏定义。取消宏定义使用:#undef<标识符>
(1) 在书写带参数的宏定义时,<宏名>与左括号之间不能出现空格,否则空格右边的部分都作为宏体。
即 #define+第一个空格+宏名+第二个空格+宏体
(2)带参数的宏定义的<宏体>应写在一行上,如果需要写在多行上时,在每行结束时,使用续行符 “\”结束,并在该符号后按下回车键,最后一行除外。
(3)定义带参数的宏时,宏体中与参数名相同的字符串适当地加上圆括号是十分重要的,这样能够避免可能产生的错误,主要是优先级错误。
(4)定义带参数的宏后,使用时最好避免使用表达式传参(直接替换,不计算表达式)。这样可以在复杂的宏定义中避免(3)中出现的问题,

IV 宏的优缺点
宏常量: 可读性好 ,便于修改,没有类型,不利于调试,
宏函数:不是函数(函数要分配临时内存单元,保留现场,值传递,,返回,恢复现场)
因为函数的调用必须要将程序执行的顺序转移到函数所存放在内存中的某个地址,将函数的程序内容执行完后,再返回到转 去执行该函数前的地方。这种转移操作要求在转去执行前要保存现场并记忆执行的地址,转回后要恢复现场,并按原来保存地址继续执行。
不分配内存, 减少运行时间(因为宏替换只占用编译时间,不占用运行时间),
没有参数类型检测,导致代码膨胀;不利于调试、宏不能访问对象的私有成员。
宏的作用域值是全局范围,并且不能限制在一个命名空间里面 ,所有在函数内或者命名空间内的#define 没啥意义

V 内联函数(效率和安全的折中)
内联函数从源代码层看,有函数的结构,而在编译后,却不具备函数的性质。内联函数不是在调用时发生控制转移,而是在编译时将函数体嵌入在每一个调用处。编译时,类似宏替换,使用函数体替换调用处的函数名。一般在代码中用inline修饰,但是能否形成内联函数,需要看编译器对该函数定义的具体处理。
内联扩展是用来消除函数调用时的时间开销。它通常用于频繁执行的函数。一个小内存空间的函数非常受益。

如果没有内联函数,编译器可以决定哪些函数内联。程序员很少或没有控制哪些只能是内联的,哪些不是。给这种控制程度,作用是程序员可以选择内联的特定应用。
使用内联函数的时候要注意:
1.递归函数不能定义为内联函数
2.内联函数一般适合于不存在while和switch等复杂的结构且只有1~5条语句的小函数上,否则编译系统将该函数视为普通函数。
3.内联函数只能先定义后使用,否则编译系统也会把它认为是普通函数。
4.对内联函数不能进行异常的接口声明。
5. 内联函数必须是和函数体申明在一起,才有效。只声明 inline int max(int x,int y);这样是没用的;
对于这种情况:在类内声明函数不必加 inline 具体实现的时候外面加inline就可以了;
6.在C++中,在类的内部定义了函数体的函数,被默认为是内联函数。而不管你是否有inline关键字。
7.内联函数的定义必须出现在内联函数第一次被调用之前。
8.内联函数只在当前文件有作用。相当于前面加了一个static,在一个文件中定义的内联函数不能在另一个文件中使用。它们通常放在头文件中共享。
9. 定义内联成员函数时,在成员函数定义前加上 inline 关键字,并且将定义放入头文件中
10.内联函数写成模板。就可以像宏那样,到处用了

VI内联函数和宏的区别:
内联函数和宏的区别在于,宏是由预处理器对宏进行替代,而内联函数是通过编译器控制来实现的。而且内联函数是真正的函数,只是在需要用到的时候,内联函数像宏一样的展开,所以取消了函数的参数压栈,减少了调用的开销。你可以象调用函数一样来调用内联函数,而不必担心会产生于处理宏的一些问题。

#define   MAX(a,b)   ((a)>(b)?(a):(b))int a=5,b=3MAX(++a,b); //a被加了两次MAX(++a,b+4); //a被加了一次

VII 用const代替宏常量
1.对于类的专属常量 定义为 :
static const 类型 常量名 = xxx;vs2013下 只有整型和char型能在类内初始化,其余不允许;
或者在 类内:static const 类型 常量名&&类外 const 类型 类名::常量名=xxx;
在类外定义初始化的变量必须给出作用域,只有const可以在类内初始化
关于 const和 static —–>专题 static&const

0 0
原创粉丝点击