小弟刚学C 有个问题不太明白
以前是做PHP的 所以对于include 来说 如果是单入口的项目 只要include一次 需要的文件就好了 其他地方不需要引入
但是C 好像也是单入口的 从main函数开始 那么为什么要每个文件都包含一次头文件呢
比如说
main.c
#include<stdio.h>
#include"mystock.h"
a.c
#include<stdio.h>
#include"mystock.h"
b.c
#include<stdio.h>
#include"mystock.h"
如果说 三个文件都用了上面两个头文件的函数 那么要包含三次 但是其实入口都是从main开始 可不可以直接main包含了这个头文件 其他文件什么都不包含呢? 对这块真是太搞不明白了
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号
这个地方你需要了解下编译原理了,首先C/C++和PHP的区别
1) 一个是动态语言(PHP),一个是静态语言(C++)
2) C/C++编译的基本单位是文件,其中采用的是声明和实现分离的方式,这里的声明你可以理解为接口的一种抽象,声明是.h,实现在.c里。 对于 "stdio.h"和“mystock.h”,C++编译器做的首先是根据main.c、a.c、b.c里对着2个头文件的使用进行词法分析、语法分析等,然后编译出一个中间文件obj,编译没问题了再链接,这是有别于PHP的,所以在编译的时候这3者文件可能都被扫描了(是否完全扫描取决于编译器的实现),但最后链接的时候,这3者的实现在内存中是只有一份的。
以下是我对 c 语言 include 的理解,我也不知道对题主是否有帮助,之所以写这么多是因为我当初对这一点也比较困惑,现在自认为弄清楚了,所以啰哩啰嗦的整理了一下。当然,我的理解不一定是正确的,请各位想要阅读的朋友带着怀疑的眼光,如有错误希望指出。
C 语言中头文件(一般情况下)是用来写函数声明的,一般不会涉及函数的具体实现等。所以如果一个头文件被包含多次,无疑会导致同一个(或一组)函数的原型被重复声明被多次。但你要知道重复声明同一个函数并不是一个错误,只有重复定义同一个函数才会报错。例如像下面这样重复声明是没有错误的:
但如果你像下面一样重复定义同一个函数,就会在编译时报错:
可是为什么要使用头文件来包含函数的原型声明呢? 来看下面这个例子:
假设我们有两个源文件,一个是
add.c另一个是main.c,我们需要在main.c中使add.c中定义的一个函数(int add( int a, int b)),下面给出两个文件的代码:保存以上两个文件后,我们就可以使用编译器来编译程序了, 注意这里我们并没有使用头文件 ,但我们照样可以编译出可执行程序,以
gcc编译器为例(vc6 也是可以的),编译命令如下:可以看到,没有头文件我们也能完成编译,头文件似乎没有必要。但现在我们修改一下
main.c看看会发生什么:在这里我们故意使用 错误的参数类型 以及 错误的参数个数 去调用
add函数,按理来说,如果这个时候我们进行编译,编译器一定会为我们指出错误。但是,如果你真的这么做了,你会发现编译器根本不会报错。原因是编译器根本不知道add函数的原型 ---- 也就是不知道add函数的返回值类型、参数个数以及每个参数的类型。对于不知道原型的函数,编译器假定该函数的返回值类型为整型,且不对其参数进行检查。所以即使我们调用add时使用的参数不正确,我们也能通过编译,但是这个程序显然在逻辑上是错误的,遗憾的是由于我们书写代码不规范,编译无法为我们发现这个错误。为了规范代码,我们应该在调用函数前给出函数的原型,以使编译器为我们检查参数。修改后的main.c如下:在上面的代码中,我们添加了函数的原型的声明,再次编译时,编译器就会为我们指出错误。
现在假设我们又添加了一个源文件
newfile.c,我们准备在这个新文件中使用add函数,为了使编译器为我们检查参数,我们不得不在newfile.c的头部书写add函数的原型。如果有一天我们把add更名为plus那我们同时也必须修改main.c和newfile.c中的原型和调用。如果有 50 个源文件中都使用了这个函数,我们至少要修改 100 次(原型 + 调用)。如果我们使用头文件的话,我们只需在头文件中书写一次函数原型,并在各个源文件中 include 这个头文件就行了。当修改函数原型的时候,只需修改头文件中的一个原型即可,当然各个源文件的调用还是要改的。于是我只需修改 51 次即可。但是,讲道理的话,其实修改 51 次和 100 次根本就没有本质上区别。可是如果add.c中有 100 个函数且其他每个源文件中都会用到这 100 个函数中的某 80 个函数呢?你愿意在每个源文件中书写 80 次函数的原型吗?更明智的做法恐怕是使用一个头文件来保存这 100 个函数的原型,然后在每个源文件中分别 include 一次这个头文件即可。这样做不仅便于维护,也更节省磁盘空间。还有就是,c 语言中的
#include是一个预处理指令,也就是说它会在正式编译之前被编译器处理掉,真正编译的是处理后代码。而对#include的处理只不过是把#include所在行替换为它所 include 的文件的内容而已,比如有以下的头文件和源文件:经过预处理后的文件如下:
综上所述,多次包含同一个头文件并不会降低最终程序的性能,也不会导致编译错误(假定头文件中只有声明没有定义,如果有定义的话,多次包含将会导致重定义,从而出错)。多次包含同一个头文件会增加预处理的时间,但是相比之下这点时间又算得了什么呢?
避免重复链接的办法是
或者在头文件开头写
后者不一定通用,前者是所有编译器都通用的。
C语言里面的
include是真的把文件加入到当前文件里面了。所以有时会看到include一个图片(数组形式)等等。所以头文件一般都会用#ifdef #endif包起来。理论上讲,如果编译的顺序是一定的,确实可以只
include一次。但往往大型的项目这样做是不可能的。看完这篇文章你就懂了 ,不只头文件,连extern,static 你都会知道怎么用
《帮 C/C++ 程序员彻底了解链接器》