随笔 - 441  文章 - 0  评论 - 10  阅读 - 51万

C语言丨引入头文件时,这个细节你注意到了吗?

今天说一个我在工作时候发现的一个细节,可能大家都已经清楚的知道了,我就在这里记录一下吧。不想看过程的直接去文末看结论吧。

声明一下:以下源文件就是.c文件,头文件就是.h文件。


 

编程规范规定,头文件里面不能include其他文件,只能在源文件中include使用到的头文件,防止头文件重复包含。对于我这种平时没这个规范习惯的人来说,就有疑问了。假如我有头文件a.h和b.h,a.h中定义了一个结构体数据类型,而我在b.h中是要使用这个数据类型的,一般情况我会直接在b.h这个头文件中包含a.h。这样就可以正常使用了,如果头文件不包含头文件的话,只在源文件中包含,这样能使用吗?会不会报错?

例如:源文件mian.c中包含了头文件a.h和b.h,头文件b.h中需要引用a.h中的数据结构类型。通过这种关系我自己做了一个检验。

a.h文件中定义了一个结构体类型,内容如下:

/*file: a.h*/

#ifndef __A_H__

#define __A_H__

typedef struct a{

    int a;

} A_S;

#endif

a.h定义了一个关于学生的一个结构体类型,然后我们需要在b.h中使用这个类型,但是b.h中不直接包含,内容如下:

/*file: b.h*/

#ifndef __B_H__

#define __B_H__

typedef struct b{

    int b;

    A_S sa;

}B_S;

#endif

b.h文件中定义了一个小组的结构体类型。SRU_S类型并没有在b.h中定义,也没有包含有定义此结构体的文件。然后我们在main.c中使用b.h中的结构。

main.c 内容如下:

/*file: main.c*/

#include <stdio.h>

#include "a.h"

#include "b.h"

int main()

{

    B_S sb;

    sb.b = 1;

    sb.sa.a = 99;

    printf("sb.b: %d\n sb.sa.a: %d\n", sb.b, sb.sa.a);

    return 0;

}

根据以上内容,直接进行gcc编译,是可以直接通过的:

hehk@hehk:~/test/C/test_include$ gcc main.c

hehk@hehk:~/test/C/test_include$ ./a.out

sb.b: 1

sb.sa.a: 99

如果我们main.c中的头文件包含a.h和b.h的位置调换一下,先包含b.h再包含a.h。如下所示:

#include "b.h"

#inlcude "a.h"

然后编译就报错了,提示如下:

hehk@hehk:~/test/C/test_include$ gcc main.c

In file included from main.c:3:0:

b.h:8:5: error: unknown type name ‘A_S’

    A_S sa;

    ^~~

main.c: In function ‘main’:

main.c:10:7: error: request for member ‘a’ in something not a structure or union

  sb.sa.a = 99;

      ^

main.c:12:52: error: request for member ‘a’ in something not a structure or union

  printf(" sb.b: %d \n sb.sa.a: %d \n", sb. b, sb.sa.a);

由此可见,得出一下结论:

头文件中没有必要include其他头文件,可以都在源文件中进行include。

头文件被include的顺序很重要,被别的头文件引用的头文件一定要先include。

去了解一下编译过程就知道了,在编译过程中有一个环节是预编译,就是来处理以"#"开始的预编译指令,其中对#include的处理规则如下:

处理 “#include” 预编译指令,将被包含的文件插入到该预编译指令的位置,此过程是递归进行的,也就是说被包含的文件可能还包含其他文件。

由此可见,引入头文件跟我们定义变量差不多,要先定义然后才能在下面使用,这样就简单明了了。


 

最后,如果你也想成为程序员,想要快速掌握编程,赶紧加入学习企鹅圈子!

里面有资深专业软件开发工程师,在线解答你的所有疑惑~编程语言入门“so easy”

编程学习书籍:


 

编程学习视频:


 
posted on   沐歌爱编程  阅读(986)  评论(1编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示