头文件

1.头文件的定义

.h为后缀的文件

一般而言,每个C++/C程序通常由头文件定义文件组成。头文件作为一种包含功能函数、数据接口声明的载体文件,主要用于保存程序的声明,而定义文件用于保存程序的实现。

2.头文件的作用

头文件的主要作用在于多个代码文件全局变量(函数)的重用、防止定义的冲突,对各个被调用函数给出一个描述,其本身不需要包含程序的逻辑实现代码,它只起描述性作用,用户程序只需要按照头文件中的接口声明来调用相关函数或变量,链接器会从库中寻找相应的实际定义代码。

3.头文件的组成

(1)头文件开头处的版权和版本声明;

(2)预处理块;

(3)inline函数的定义;

(4)函数和类结构声明等。

ifndef/define/endif结构产生预处理块,用 #include 格式来引用库的头文件

4.头文件的使用#include

(1)头文件的调用

#include 指令会指示 C 预处理器浏览指定的文件作为输入。预处理器的输出包含了已经生成的输出,被引用文件生成的输出以及 #include 指令之后的文本输出。

#include <stdio.h>
#include "my.h"

<>表示引用的是编译器的类库路径里面的头文件

""表示引用的是你程序目录的相对路径中的头文件,如果在程序目录没有找到引用的头文件则到编译器的类库路径的目录下找该头文件。

通常用户自定义的头文件是使用双引号

(2)头文件的书写

只在头文件中声明,并不具体实现,具体实现是在源文件中进行实现

**eg:**在my.h中声明函数和结构体,然后在my.cpp中进行具体实现,这样就可以直接在text.cpp中进行使用

函数的具体声明源文件不是必须和头文件相同,这只是为了看起来比较整齐,读起来也比较方便,并且有利于模块化和代码的复用性

#ifndef _MY_H_	//ifndef表示开始,如果在导入头文件的文件中之前没有导入该头文件就编译下面的代码”,该句的作用是防止重复导入
//后跟的是文件名,比如这个文件名字是my.h,用下划线包裹文件名,并且“.”也用下划线代替,所以是_MY_H_
#define _MY_H_	//宏定义,以下书写头文件主体部分
...
#endif	//和endif表示结束

(3)常用头文件(标准库)

stdio.h  标准输入输出
stdlib.h  标准常用库
string.h  字符串函数库
math.h  数学库
ctype.h  字符函数库
time.h 时间库
windows.h  微软视窗库c

(4)使用场景

  1. 结构体的定义

  2. 函数声明,变量声明,宏定义,常数定义等

  3. 当源代码不便公布时使用头文件提供接口

  4. 在大项目中需要多文件联合编译


宏定义

1.宏#define

(Macro),是一种批量处理的称谓。

宏定义将一个标识符定义为一个字符串源程序中的该标识符均以指定的字符串来代替。预处理命令后通常不加分号。这并不是说所有的预处理命令后都不能有分号出现。由于宏定义只是用宏名对一个字符串进行简单的替换,因此如果在宏定义命令后加了分号,将会连同分号一起进行置换。

宏定义的功能是在编译预处理时,对程序中所有出现的“宏名”都用宏定义中的字符串去代换,这称为“宏代换”或“宏展开”。

2.宏的定义格式

#define <宏名>(<参数表>) <宏体>

<宏名>是一个标识符,<参数表>中的参数可以是一个,也可以是多个,视具体情况而定,当有多个参数的时候,每个参数之间用逗号分隔。<宏体>是被替换用的字符串,宏体中的字符串是由参数表中的各个参数组成的表达式

#include <stdio.h>
#define ABC 2
#define SUB(a,b) a-b
#define CBA "风雨\
同舟"

//如果写不完可以使用“\”来换行
//“\”后直接按回车键换行,不能含有包括空格在内的任何字符,否则是错误的宏定义形式。
int main()
{
    printf("%d\n", ABC);    //输出为2,所有出现的ABC都用2代替
    int result = SUB(2, 3); //所有出现的SUB(2, 3)都被替换为:result = 2 - 3;
    printf("%d\n", result);
    printf("%s\n", CBA);    //输出为风雨同舟
    return 0;
}

在使用宏定义时应注意的是:

(1)带参数的宏定义的<宏体>应写在一行上,如果需要写在多行上时,在每行结束时,使用续行符"\"结束,并在该符号后按下回车键,最后一行除外。

(2)在书写带参数的宏定义时,<宏名>与左括号之间不能出现空格,否则空格右边的部分都作为宏体。

#define ADD (x,y) x+y
将会把"(x,y)x+y"的一个整体作为被定义的字符串。

(3)定义带参数的宏时,宏体中与参数名相同的字符串适当地加上圆括号是十分重要的,这样能够避免可能产生的错误

(4)定义带参数的宏后,使用时最好避免使用表达式传参。

宏函数和自定义函数相比,效率更高但是安全性低且会使编译生成的目标文件变大;宏函数没有分配和释放栈帧、传参、传返回值等一系列工作,适合那些简短并且频繁调用的函数,但是对于递归则不推荐使用宏

3.删除宏#undef

(1)删除宏的作用

#undef:取消已定义的宏

#define定义预处理器标识符,将保持已定义状态且在作用域内,直到程序结束或者使用#undef 指令取消定义。

(2)删除宏的使用

#include <stdio.h>
int main(void)
{
#define A 200
    printf("A= %d\n", A);   //输出结果为A=200
#undef A
#define A 300
    printf("A= %d\n", A);   //输出结果为A=300
    return 0;
}
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐