我不太明白 C 的源文件和头文件中的内容应该如何分开。我经常看到许多项目有两组同名的文件(一个扩展名表示源文件,另一个表示头文件)。
到目前为止,由于缺乏理解,当我编写库时,我将所有类和类方法代码都放入一个文件中,对于选择文件扩展名犹豫不决。
标头中应包含哪些内容以及源文件中应包含哪些内容?我如何实现这种分离?
没有技术差异。如果您愿意,编译器会很乐意让您包含
.c
文件,或者直接编译 .h
文件。
然而,存在巨大的文化差异:
声明(原型)进入
.h
文件。 .h
文件是相应 .c
文件中实现的任何内容的接口。
定义进入
.c
文件。他们实现在.h
文件中指定的接口。不同之处在于,一个
.h
文件可以(并且通常会)被 #include
分成多个编译单元(.c
文件)。如果您在 .h
文件中 定义函数,它将最终出现在多个
.o
文件中,并且链接器会抱怨多重定义的符号。这就是为什么定义不应该放在 .h
文件中。 (内联函数是例外。)
如果某个函数在
.c
文件中定义,并且您想从其他 .c
文件中使用该函数,则该函数的声明需要在其他每个 .c
文件中可用。这就是为什么您将声明放在 .h
中,并将 #include
放在每个声明中。您也可以在每个 .c
文件中重复声明,但这会导致大量代码重复和难以管理的混乱。
如果某个函数在
.c
文件中定义,但您不想 希望从其他 .c
文件中使用它,则无需在标头中声明它。它本质上是该 .c
文件的实现细节。在这种情况下,也将函数设为 static
,这样它就不会与其他文件中的同名函数冲突。
标头中应包含哪些内容以及源文件中应包含哪些内容?
标头通常包含以下一项或多项:
struct
、union
等)另一方面,源文件有:
如何实现这种分离?
单一定义规则是你的朋友。
请记住,如果您正在编写一个库,这就是您的客户看到的内容。因此,请提供帮助并提供所有信息,以便他们使用您的图书馆。源文件通常以二进制形式编译和提供。
顺便说一句,C 没有类的概念。
通常,头文件包含声明,源文件包含代码。
因此,如果在源文件
A.c
中您需要在源文件 B.c
中实现一个函数,则只需包含 B.h
即可获得其声明。
.c 和 .h 文件之间几乎没有根本区别(尽管某些编译器可能拒绝编译原始 .h 文件)。按照惯例,差异更大。
通常,.h 文件提供 API,.c 提供实现。
因此 .h 文件将仅包含其他源文件访问 .c 文件提供的功能所需的内容。因此 .h 文件将提供全局函数的函数原型、全局变量的声明(如果您确实必须拥有它们)以及它们使用的结构和其他类型。 (如果 API 只需要指向结构的指针,则不要公开该结构。)
内联函数也经常包含在 .h 文件中,但一些编码指南更喜欢使用单独的扩展名(例如 .inl)
所有其他函数实现、变量的定义和初始化以及局部(静态)变量和函数的声明都将位于 .c 文件中。
其他答案都很好,但我错过了一个额外因素:
源文件是带有源代码的文件,旨在转换为翻译单元。然后每个翻译单元由编译器编译成机器代码。
头文件是带有源代码的文件,旨在通过#include
预处理器指令
包含到其他文件(源文件或头文件)中。
这种区别非常重要,可能有助于理解如何分离两种类型文件之间的代码。