首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

C语言基础:头文件的使用

  • 23-09-22 01:23
  • 3019
  • 7063
blog.csdn.net

本文从汽车软件开发的角度出发,研究C语言中头文件的作用。各行各业都有自己一套规范或者约定俗成的规则,所以本文不一定适用于所有C语言开发的情形。

文章目录

  • 1 头文件的作用
  • 2 头文件的内容
    • 2.1 #define保护
    • 2.2 包含其他头文件
    • 2.3 变量与函数的声明
    • 2.4 extern “C”
  • 3 头文件使用的规范
    • 3.1 C文件和头文件
    • 3.2 调用外部函数和变量
  • 4 总结

1 头文件的作用

在C语言编程中,头文件有着十分重要的作用,最核心的作用就是对外声明函数或全局变量。初次之外,还有类型定义、宏定义等功能。

一个好的头文件设计,可以清晰地解释系统架构以及调用关系。接下来博主会从工作经验出发,研究C语言的头文件中包含哪些信息。

2 头文件的内容

2.1 #define保护

拿到一个头文件,例如vc_vehicle_speed_control.h,在顶部会看到类似如下的代码:

//vc_vehicle_speed_control.h
#ifndef VC_VEHICLE_SPEED_CONTROL_H
#define VC_VEHICLE_SPEED_CONTROL_H

//一些外部声明

#endif /* VC_VEHICLE_SPEED_CONTROL_H */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

从字面上理解,就是如果没有定义宏VC_VEHICLE_SPEED_CONTROL,那么就定义它,然后处理下面的外部声明等头文件核心内容。

这样做的目的是为了防止头文件被重复包含。在一个文件中第二次包含这个头文件时,由于已经定义过宏VC_VEHICLE_SPEED_CONTROL,在预处理阶段就不会把这个头文件中的内容展开来,就达到了防止重复包含的效果。

一般来说,这个保护用的宏地名称和头文件名称相同,但是全部改成大写。

2.2 包含其他头文件

头文件中可以包含其他头文件,这样编译器在预处理阶段就会一层层地展开内容。

例如有三个模块A,B,C实现不同功能,它们分别有三个头文件A.h,B.h,C.h。通过一个总的头文件common.h包含这三个头文件,其他模块D就可以直接包含common.h来调用这三个模块中的函数。

//common.h
#ifndef COMMON_H
#define COMMON_H

#include "A.h"
#include "B.h"
#include "C.h"

#endif /* COMMON_H */

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

另外,也有一种做法是把一些公共的宏定义或类型定义写在一个头文件中,其他头文件再去包含这个都用得到的头文件,例如包含类型定义的头文件。

//vc_vehicle_speed_control.h
#ifndef VC_VEHICLE_SPEED_CONTROL_H
#define VC_VEHICLE_SPEED_CONTROL_H

#include "common_types.h"
//一些外部声明

#endif /* VC_VEHICLE_SPEED_CONTROL_H */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

系统头文件和用户用户头文件的符号有所区别:

#include 
#include "user.h"
  • 1
  • 2

对于用户头文件,如果不在同一个路径下,最好用相对路径来表示:

#include "../module1/user.h"
  • 1

2.3 变量与函数的声明

变量与函数的声明是头文件中最重要的内容,其他文件包含头文件的目的就是为了调用这些变量和函数。例如在vc_vehicle_speed_control.h声明了对外的变量与函数接口。

//vc_vehicle_speed_control.h
#ifndef VC_VEHICLE_SPEED_CONTROL_H
#define VC_VEHICLE_SPEED_CONTROL_H

#include "common_types.h"

extern const float32 vehicle_width;

void vc_vehicle_speed_control_init(void);
void vc_vehicle_speed_control_cycle(void);

#endif /* VC_VEHICLE_SPEED_CONTROL_H */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

从上面的代码中很容易理解到,头文件外部声明了一个常量vehicle_width,数据类型是32位浮点型。声明了两个函数,一个用于初始化,一个用于周期调度,函数传参和返回值都是void类型,一目了然地知晓了对应的c文件vc_vehicle_speed_control.c中定义了哪些变量,哪些函数。在项目中,如果想要快速地熟悉软件架构和功能接口,只需要看一看头文件中的定义,以及头文件的调用关系即可。

2.4 extern “C”

extern “C” 常用于C和C++混合编程中。例如,嵌入式软件中用的C代码编程,实现某种汽车零部件功能。也可以把这段C代码拿到VisualStudio或者其他C++工程中进行编译,从而脱离嵌入式环境中仿真。

由于C++编译和C的编译规则有所不同,就需要告诉编译器哪些函数是C函数,这就要用到extern “C” 。用法如下:

//vc_vehicle_speed_control.h
#ifndef VC_VEHICLE_SPEED_CONTROL_H
#define VC_VEHICLE_SPEED_CONTROL_H

#include "common_types.h"

#ifdef __cplusplus
extern "C" {
#endif

extern const float32 vehicle_width;
void vc_vehicle_speed_control_init(void);
void vc_vehicle_speed_control_cycle(void);

#ifdef __cplusplus
}
#endif 
#
endif /* VC_VEHICLE_SPEED_CONTROL_H */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

上面的意思是,如果定义了__cplusplus这个宏,就用extern “C” {}把函数的外部声明给包裹起来,这样编译器就知道这些是C函数。

注意一点,include头文件不要写到extern “C” {}中去。

3 头文件使用的规范

博主根据自己工作经验总结一些头文件的规范。不同行业、产品、团队都可能有自己的规范,这里仅供参考。

3.1 C文件和头文件

C文件中如果有被外部引用的函数,应该有一个同名的头文件,用于外部声明一些函数。这个头文件中只有外部需要引用的接口,而不包括C文件私有的函数、宏定义、枚举量等。这些私有的定义应该放在其他的头文件中,例如如下:

//vc_vehicle_speed_control.h
#ifndef VC_VEHICLE_SPEED_CONTROL_H
#define VC_VEHICLE_SPEED_CONTROL_H

void vc_vehicle_speed_control_init(void);
void vc_vehicle_speed_control_cycle(void);

#endif /* VC_VEHICLE_SPEED_CONTROL_H */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
//vc_vehicle_speed_control_private.h
#ifndef VC_VEHICLE_SPEED_CONTROL_PRIVATE_H
#define VC_VEHICLE_SPEED_CONTROL_PRIVATE_H

typedef struct VC_VEHICLE_SPEED_TAG
{
	float32 display_vehicle_speed;
	float32 actual_vehicle_speed;
}VC_VEHICLE_SPEED;

typedef enum VC_GEAR_POSITION_TAG
{
	GEAR_P = 0;
	GEAR_N;
	GEAR_D;
	GEAR_R;
}VC_GEAR_POSITION;

#endif /* VC_VEHICLE_SPEED_CONTROL_PRIVATE_H*/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

其中,车速和挡位是C文件私有的类型,就放在_private.h中,只被自己的c文件调用。对外声明接口的头文件,可以被外部调用。

另外指出一点,调用其他文件的函数时,只能通过包含头文件(因为头文件中有外部声明函数),不应该在自己的文件中直接extern声明函数。

3.2 调用外部函数和变量

调用外部函数和变量的时候,必须通过包含其头文件的方式调用,而不能在自身中直接用extern语句进行外部声明(即使语法运行这么做)。例如下面的周期调度文件调度一个任务函数。

//OS.c
extern void vc_vehicle_speed_control_cycle(void);

void Task_20ms(void)
{
	vc_vehicle_speed_control_cycle();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在OS.c文件中想要把vc_vehicle_speed_control_cycle();函数加入20ms的周期调度中,但是没有包含头文件,直接extern声明。这样是不合理的,因为没有表现出各个文件之间的依赖关系。

正确做法如下:

//OS.c
#include "vc_vehicle_speed_control.h"

void Task_20ms(void)
{
	vc_vehicle_speed_control_cycle();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
//vc_vehicle_speed_control.h
#ifndef VC_VEHICLE_SPEED_CONTROL_H
#define VC_VEHICLE_SPEED_CONTROL_H

void vc_vehicle_speed_control_init(void);
void vc_vehicle_speed_control_cycle(void);

#endif /* VC_VEHICLE_SPEED_CONTROL_H */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

4 总结

C语言头文件的知识不止于此,后续博客会在工作和实践过程中积累并更新。

>>返回个人博客总目录

文章已被收录至官方知识档案
C技能树函数与程序结构头文件160872 人正在系统学习中
注:本文转载自blog.csdn.net的chhttty的文章"https://blog.csdn.net/u013288925/article/details/106891382"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2491) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top