头文件编译源码-如何理解C语言中的“.h”文件和“.c”文件?看了详细分析,小白就能明白

简单来说,当然,要了解C文件和头文件(即.h)的区别,首先需要了解编译器的工作过程。 一般来说,编译器会做以下几个过程:

1. 预处理阶段

2.词法和句子分析阶段

3、编译阶段,先编译成纯汇编语句,然后编译成与CPU相关的二进制代码,生成各个目标文件(.obj文件)

4、链接阶段,对每个目标文件中的每段代码进行绝对地址定位,生成与特定平台相关的可执行文件。 当然,objcopy也可以用来在最后生成纯二进制代码,即去掉文件格式信息。 (生成.exe文件)

编译器是以C文件为单位进行编译的,也就是说,如果你的工程中没有C文件,那么你的工程将很难编译,而链接器是基于目标文件的。 每个目标文件都会重新定位函数和变量以生成最终的可执行文件。 一般来说,PC上的程序开发有一个主要功能。 这是各个编译器的约定。 当然,如果你自己编写链接描述文件的话,你可以使用main函数作为程序入口点! ! ! !

(main.c文件目标文件可执行文件)

有了这些基础知识,我们就开始正题吧,为了生成一个最终的可执行文件,需要一些目标文件,也就是需要一个C文件,而这个C文件需要一个main函数作为可执行程序,那么我们先从一个C文件开始,假设这个C文件的内容如下:

#包括

#include“mytest.h”

int main(int argc, char **argv)

测试=25;

printf("测试..............%dn",测试);

mytest.h头文件内容如下:

内部测试;

现在用这个例子来解释一下编译器的工作:

1、在预处理阶段,编译器以C文件为单位,首先读取C文件,发现第一句和第二句包含头文件,并在所有搜索路径中搜索这两个文件。 找到后,会对对应头文件中的宏、变量、函数声明、嵌套头文件包含等进行处理,检测依赖关系,进行宏替换,检查是否存在重复的定义和声明。 最后,这些文件中的所有东西都会被扫描到当前这个C文件中,形成一个中间“C文件”

2.在编译阶段,在上一步中,相当于将头文件中的test变量扫描到一个中间C文件中,那么test变量就成为这个文件中的全局变量,以及所有中间的所有变量和C文件的函数分配空间,将各个函数编译成二进制代码,根据具体的目标文件格式生成目标文件,对这些格式的目标文件中的各个全局变量和函数进行符号描述,编译成二进制代码按照一定的标准组织成目标文件

3、连接阶段,根据一些参数将上一步生成的目标文件连接起来,生成最终的可执行文件。 主要任务是重新定位各个目标文件的函数和变量,相当于将二进制代码按照一定的规范组合成一个文件,然后回到C文件和头文件要写什么内容的主题file:理论上来说,只要C文件和头文件中的内容是C语言支持的,无论写什么内容都是可以的,比如把函数体写在头文件中,如下只要任何C文件中包含这个头文件,该函数就可以编译成目标文件的一部分(编译是基于C文件的,如果不在任何C文件中包含这个头文件的话,这段代码没用),您可以在 C 文件中声明函数、变量和结构,这不是问题! ! !

那为什么一定要分为头文件和C文件呢? 为什么函数、变量声明、宏声明和结构体声明通常在头文件中执行? 而在C文件中定义变量,那么函数实现呢? ? 原因如下:

1.如果一个函数体是在头文件中实现的,如果在多个C文件中引用,并且同时编译多个C文件,则生成的目标文件链接成可执行文件,并且每个引用在对象中这个头文件的C文件生成的文件中,有这个函数的代码。 如果这个函数没有被定义为局部函数,那么在链接的时候,会发现多个相同的函数,就会报错。

2. 如果在头文件中定义全局变量并将最终值赋给该全局变量,则在引用该头文件的多个 C 文件中存在相同变量名的副本。 关键是这个变量被赋予了一个最终值。 因此,编译器会将这个变量加载到DATA段中。 最后,在连接阶段,DATA段中会出现多个相同的变量。 它未能将这个变量统一为一个变量,即只为这个变量分配一块空间。 而不是多个空格,如果在头文件中没有为该变量分配最终值,则编译器将加载它

在BSS段中,链接器只会为BSS段中的多个同名变量分配一块存储空间。

3、如果在一个C文件中声明了宏、结构体、函数等,那么我如果要在另一个C文件中引用相应的宏或结构体,就必须再次做重复的工作。 如果我改变了一个C文件,而忘记改变其他C文件中的声明,那么就会出现很大的问题,程序的逻辑将变得难以想象。 如果你把这种公共的东西放在一个 header 文件中,如果你想使用它的 C 文件,只需要引用一个就可以了! ! !这样是不是很方便,当你想改变某个声明的时候,只需要动一下头文件就可以了

4、在头文件中声明结构体、函数等。 当你需要将你的代码打包成库让别人使用你的代码,而你又不想发布源代码时,别人怎么能使用你的库呢? 也就是如何使用你的库中的各种函数? ? 一种方法是发布源代码,其他人可以随意使用。 另外就是提供头文件,别人可以从头文件中读取你的函数原型,这样就知道如何去调用你写的函数,就像你调用printf函数一样,里面的参数是什么? ? 你怎么知道? ? 不是看别人头文件中的相关声明! ! ! 当然,这种东西已经成为了C标准,即使你不读别人的头文件,你仍然可以知道如何使用它。

C语言中.c和.h文件的困扰

本质上没有区别。但通常情况下:.h文件是头文件,其中包含函数声明、宏定义、结构体定义等。

.c文件是一个程序文件,其中包含函数实现、变量定义等。 无论是哪个后缀,编译器都会默认对具有单独后缀的文件采取单独的操作。 您可以强制编译器将任何后缀的文件编译为 c 文件。

分别编写这两个文件是一种很好的编程风格。

而且,例如,我在aaa.h中定义了一个函数声明,然后我在与aaa.h相同的目录中构建了aaa.c。 这个函数的实现是在aaa.c中定义的,然后main函数位于.c文件中#include这个aaa.h就可以使用这个函数了。 Main会在运行时找到定义该函数的aaa.c文件。

这是因为:

main函数是标准C/C++程序的入口点,编译器首先会找到该函数所在的文件。

假设编译器在编译myproj.c(其中包含main())时,发现其中包含了mylib.h(其中声明了函数void test()),则编译器将按照预设路径(包括路径列表和代码文件所在路径)查找同名的实现文件(扩展名为.cpp或.c,本例为mylib.c),如果找到则查找函数(本例为void test()),继续编译; 如果在指定目录中找不到实现文件,或者在该文件及后续包含文件中找不到实现代码,则返回编译错误。 其实include的过程完全可以“思考”,就是一个拼接文件的过程。 声明和实现分别写在头文件和C文件中,或者两者同时写在头文件中,理论上没有本质区别。

以上就是所谓的动态方法。

对于静态方法,基本上所有的C/C++编译器都支持一种称为Static Link的链接形式,简称静态链接。

在这些方法下,我们要做的就是编写包含函数、类等声明的头文件(ah、bh、...),以及它们对应的实现文件(a.cpp、b.cpp、.. . .),编译器会将其编译成静态库文件(a.lib,b.lib,...)。 在以后的代码复用过程中,我们只需要提供相应的头文件(.h)和相应的库文件(.lib),就可以使用过去的代码了。

与动态方法相比,静态方法的好处是实现代码的隐蔽性,即C++中提倡的“接口对外,实现代码不可见”。 有利于库文件的转发。

许多人可能会反对说这个谜题最难的部分是基本概念,但这是事实。 我中学化学的时候,老师注重的是概念,概念一定要弄清楚,困难的问题就变成了简单的问题。 如果你能分析清楚,一个化学困境中有几个化学过程,并且每个过程都遵守那个数学定理(如动量守恒、牛II定理、能量守恒),那么根据定理枚举这个过程就很容易了。 式中,N个过程必须是N个N元多项式,问题就很容易解决。 即使是中学物理竞赛的困境,最难的也无非是:

(1)概念混乱,难以分析几种化学过程,或者某种化学过程所遵循的数学定理;

(2)存在高阶方程,即使列出多项式也无法求解多项式。 后者早已属于物理学的范畴,所以最难的是掌握一个清晰的概念;

对于编程来说也是如此。 如果概念清晰的话,基本上没有什么困难(物理上会比较难,比如算法的选择,时间、空间和效率的选择,稳定性和资源的平衡)。 然而,掌握清晰的概念并不那么容易。 比如下面这个反例,看看你是否理解的清楚透彻。

//啊无效foo(); //ac #include "ah" //我的问题来了:这句话是必须的吗?

无效 foo()

{ 返回; } //main.c #include "ah" int main(int argc, char *argv[]) {foo(); 返回0; }

对于里面的代码,请回答三个问题:

。 (1)ac中的#include“ah”这句话是多余的吗?

(2)为什么经常看到xx.h对应include在xx.c中?

(3)如果不是用ac写的,编译器会手动将.h文件的内容绑定到同名的.c文件上吗? (惯于)

头文件编译源码-如何理解C语言中的“.h”文件和“.c”文件?看了详细分析,小白就能明白

(里面的3个问题请仔细思考10分钟,不要急于看下面的解释。:)你想得越多,理解就越深刻。 )

好吧,是时候了! 请忘记里面的3个问题,以及你对这三个问题的看法,然后慢慢听我说。 正确的概念是:从C编译器的角度来看,.h和.c都是浮云,即使改名为.txt或.doc也没有太大区别。 也就是说,.h和.c之间没有必然联系。 .c文件中定义的同名变量、数组、函数的声明通常放在.h中,而需要在.c之外使用的声明。 这个声明有什么用呢? 只是为了方便引用需要使用此类语句的地方。 因为宏#include "xx.h"的实际含义是删除当前行,并将xx.h中的内容原封不动地插入到当前行的位置。 由于要写这种函数声明的地方太多了(凡是调用xx.c中函数的地方,都必须先声明再使用),所以使用#include "xx.h"宏简化了许多代码行——让预处理器替换它自己。 也就是说,xx.h实际上只是调用了xx.c中需要编写函数声明的地方(可以省几行书写)。 至于.h文件要包含谁,是.h还是.c,还是和这个有关。 同名的h和.c没有必然关系。

那么你可能会说:啊? 然后我通常只想调用xx.c中的某个函数,但我包含了xx.h文件。 宏替换后不是有很多无用的声明吗? 是的,它确实引入了很多垃圾,但是却节省了你很多笔,而且整个布局看起来清新很多。 这就是鱼和熊掌不可兼得的原因。 反正少声明(.h一般只用来放声明,不放定义,见我的书《过马路,左看看右》)是没有用的,而且不会影响编译,何乐而不为呢?

回头看看里面的3个问题,很容易回答吧? 答:不一定。 在这种情况下,它实际上是多余的。 但如果.c中的函数还需要调用同一个.c中的其他函数,那么这个.c中往往会包含同名的.h,这样就不用担心声明的顺序了调用(C语言要求必须声明,并包含同名的。h通常放在.c的开头)。 很多项目甚至都同意这些编写方法作为代码规范,以规范清晰的代码。

回答:1已经回答了。

答:不是。问这个问题的人肯定是不清楚,或者只是想浑水摸鱼。 我非常讨厌的是中国很多考试都有这些烂问题。 生怕别人概念不清,一定会让考生感到困惑。

弄清楚句型和概念说起来容易做起来难,但说起来也很难。 有三招:不要发呆,花时间思考,多读书;

读书读好书,问人问强人。 坏书、坏人会给你错误的观念,误导你;

勤奋可以弥补不足是一种很好的修养,一分耕耘一分收获;

(1)通过头文件调用库函数。 很多场合,源代码不方便(或者不允许)发布给用户,只要提供头文件和二进制库给用户即可。 用户只需根据头文件中的socket声明来调用库函数,而不需要关心socket是如何实现的。 编译器从库中提取相应的代码。

(2)头文件可以加强类型安全检测。 如果一个socket在实现或使用时头文件编译源码,其形式与头文件中的声明不一致,编译器会强调该错误,这个简单的规则可以大大减轻程序员调试和纠错的负担。

头文件用于存储函数原型。

头文件与源文件有何关系?

头文件编译源码-如何理解C语言中的“.h”文件和“.c”文件?看了详细分析,小白就能明白

这道题其实是说已知的头文件“ah”声明了一系列函数(只有函数原型,没有函数实现),而这个函数是在“b.cpp”中实现的,那么如果我想在“c”中使用它.“cpp”中“ah”中声明的、在“b.cpp”中实现的函数通常在“c.cpp”中使用#include“ah”,那么c.cpp如何找到b.cpp的实现呢?

事实上,.cpp 和 .h 文件名之间没有直接关系,许多编译器可以接受其他扩展名。

谭浩强先生的《C程序设计》一书中提到,编译器预处理时,#include命令应该是“文件包含”:将headfile.h的全部内容复制到#include

“头文件.h”。 这也解释了为什么很多编译器并不关心这个文件的后缀是什么——因为#include预处理就是完成一个“复制并插入代码”的工作。

程序编译时不会在b.cpp文件中查找函数实现,只有在链接时才做这项工作。 我们在b.cpp或者c.cpp中使用#include "ah"来实际引入相关声明,这样编译就可以通过,程序并不关心在哪里实现以及如何实现。 源文件编译后,会生成目标文件(.o 或 .obj 文件)。 在目标文件中,这些函数和变量被视为符号。 链接的时候需要在makefile上指明需要链接哪个.o或者.obj文件(这里是b.cpp生成的.o或者.obj文件),这时候链接器就会去这个.o或者 .obj 文件中找到 b.cpp 中实现的函数,然后将其构建成 makefile 中指定的可执行文件。 (很重要)

在VC中,有些情况下你不需要自己写makefile,你只需要在工程中包含所有需要的文件,VC就会帮你手动写makefile。

通常,编译器会在每个 .o 或 .obj 文件中查找所需的符号,而不是只在某个文件中查找或说如果找到了就不再查找。 因此头文件编译源码,如果在几个不同的文件中实现相同的功能,或者定义相同的全局变量,则链接时会提示“redefine”。

最后,无论你是在职场成长,还是在大学入门阶段,C/C++都是一门既能强化你的思维能力,又能为编程打下坚实基础的编程语言。 如果你想做软件开发,成为核心程序员,学习C/C++是更好的选择。 作者有一个上千人的C/C++编程Q群(Q船索:C语言编程学习聚集地(无声建设))如果你觉得自学C/C++语言有困难如果你有兴趣学习或者学习C/C++编程,可以进来交流。 给大家分享一下C/C++的学习路线图:

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悟空资源网 源码编译 头文件编译源码-如何理解C语言中的“.h”文件和“.c”文件?看了详细分析,小白就能明白 https://www.wkzy.net/game/163106.html

常见问题

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务