C语言中include的冷知识——聊聊大家熟悉又陌生的include
摘自:https://mp.weixin.qq.com/s/4e8_0SK4mrInJq1dEy4lFQ
不管你是初学者还是高手,在学习了解C语言的时候,都学过include这个知识。
而我们最熟悉最常见的热知识,无非就这么几句话描述。
include就是包含头文件的意思。
而这个头文件,一般是系统头文件,第三方库的头文件,以及自定义用户头文件。
包含的形式,一般是在c文件的开头,进行include。
包含的形式编写则是:
#include <stdio.h>
#include <abc0.h>
#include “abc1.h”
其中,<> 包含和””包含的区别就是””会优先寻找当前目录是否存在该头文件,如果当前目录没有,则会在系统目录以及工程配置头文件包含目录寻找。
而<>则是会在系统目录以及工程配置包含目录寻找。
好了热知识讲完了。嗯,大家离C语言高手又进一步了。到这里,有时候在招聘面试一些新人的时候,他们回答这个问题,甚至都眼含高光,已然是一副编程高手的样子了。
有的人就会说,C语言的include了解到这里就行了呀。再深入的没必要呀。编程够用了呀。
那我们对这个include展开几个问题,看大家面试的时候,有没有遇到过,或者平时有没有思考过。
0 include既然是包含头文件,是怎么个包含的。
1 include 必须在文件的开头么,可以在文件任意位置,甚至结尾么。
2 include 只能包含.h 文件么,能包含.c文件么,能包含任意文本文件么。
3 include 可以重复包含么。
4如果a.h里包含b.h,同时b.h里包含a.h,会出现循环嵌套包含么。
Q
0 include既然是包含头文件,是怎么个包含的。
我们通常了解到的内容,是编译器会自动去寻找头文件,把头文件包含进来编译。
但具体是这怎么个包含法呢。
编译器,一般是先将c文件,编译成o文件,再将o文件经过一系列操作,变成可执行文件或者静态/动态库。
那么,编译器怎么知道头文件呢。
那就是在编译的时候,找到include关键字段。比如include “abc1.h”,编译器找到了abc1.h这个文件了,会怎么呢。
举个例子:
abc1.h文件内容为:
#define ABC 123
#define HAHAHAHA
就两行内容
main.c文件内容为:
#include “abc1.h”
int main()
{
int a=ABC;
return 0;
}
通过编译器的包含之后,假如会生成一个新的临时c文件,就是
tmp_main.c,内容为:
#define ABC 123
#define HAHAHAHA
int main()
{
int a=ABC;
return 0;
}
然后再编译这代码。
所以,include的包含,可以理解为,将include的文件里的内容复制,并粘贴在当前位置。
带着这个知识和理解,我们就可以继续回答下面的问题了。
AQ
1 include 必须在文件的开头么,可以在文件任意位置,甚至结尾么。
在上一个问题里,include的本质,就是将include的文件,在当前位置展开。那么,就很好理解了。
对于编译器来说,不去管include在哪个位置,都是执行同样的操作。
所以,include可以在文件任意位置的。
AQ
include 只能包含.h 文件么,能包含.c文件么,能包含任意文本文件么。
还是include的本质,既然是将对应的文件的文本内容在当前位置展开,就意味着,并不是只能include .h文件,也可以include .c 文件。只是如果一般来说,include .c文件,相当于把两个或者多个c文件,合并到一个c文件,好处就是只需要编译总的c文件,被包含的c文件可以不需要编译。
甚至也可以include 任意文本文件,include .txt文件,include .ini文件都没问题。
AQ
3 include 可以重复包含么。
可以重复包含的。
比如在main.c里这样写:
#include <stdio.h>
#include <stdio.h>
#include “abc1.h”
#include “abc1.h”
因为编译器不关心这么多,只需要检测到include,并展开相应的文件内容即可。
至于重复包含,是否会报错,具体就看头文件写的怎么样。
被了避免重复被包含出现错误,一般头文件会加宏定义。
比如abc1.h文件:
#define ABC 123
#define HAHAHAHA
加了宏定义之后这样:
#ifndef __ABC1_H__
#define __ABC1_H__
#define ABC 123
#define HAHAHAHA
#endif
一般加了#ifndef/#define/#endif之后,重复包含也不会有问题了。
还是建议养成良好编程习惯
AQ
如果a.h里包含b.h,同时b.h里包含a.h,会出现循环嵌套包含么
如果没有加#ifndef/#define/#endif的话,就会出现循环嵌套包含,编译的时候,会报错。
b.h:3:15: error: #include nested too deeply
有提示.h文件嵌套太深了。
所以,在编程习惯上,对于.h文件,要记得加#ifndef/#define/#endif,养成良好编程习惯。
浙公网安备 33010602011771号