【发布时间】:2010-08-14 10:42:04
【问题描述】:
我不太明白应该如何在 C 的源文件和头文件中分离内容。我经常看到很多项目有两组同名文件(一个扩展名表示一个源,另一个捐赠一个头文件)。
到目前为止,由于缺乏理解,当我编写库时,我已经将所有类和类方法代码放入一个文件中,犹豫不决选择文件扩展名。
什么应该在头文件中,什么应该在源文件中?如何实现这种分离?
【问题讨论】:
标签: c
我不太明白应该如何在 C 的源文件和头文件中分离内容。我经常看到很多项目有两组同名文件(一个扩展名表示一个源,另一个捐赠一个头文件)。
到目前为止,由于缺乏理解,当我编写库时,我已经将所有类和类方法代码放入一个文件中,犹豫不决选择文件扩展名。
什么应该在头文件中,什么应该在源文件中?如何实现这种分离?
【问题讨论】:
标签: c
没有技术差异。编译器很乐意让您包含一个.c 文件,或者如果您愿意,可以直接编译一个.h 文件。
然而,存在巨大的文化差异:
声明(原型)进入.h 文件。 .h 文件是对应.c 文件中实现的任何内容的接口。
定义进入.c 文件。他们实现.h文件中指定的接口。
不同之处在于.h 文件可以(并且通常会)将#included 转换为多个编译单元(.c 文件)。如果您在.h 文件中定义 一个函数,它将在多个.o 文件中结束,并且链接器将抱怨多重定义的符号。这就是为什么定义不应该放在.h 文件中的原因。 (内联函数是个例外。)
如果在.c 文件中定义了一个函数,并且您想从其他.c 文件中使用它,则该函数的声明需要在每个其他.c 文件中可用。这就是为什么您将声明放在.h 和#include 中的原因。您也可以在每个 .c 文件中重复声明,但这会导致大量代码重复和无法维护的混乱。
如果在.c 文件中定义了一个函数,但您不想从其他.c 文件中使用它,则无需在标头中声明它。它本质上是那个.c 文件的实现细节。在这种情况下,请将函数 static 也设置为,这样它就不会与其他文件中的同名函数冲突。
【讨论】:
int main(){return 0;})的文件,分别称为header.c 和header.h,并尝试用gcc 编译它们。 (我什至没有接近 VS!)
gcc -Wall -ansi -pedantic -std=c99 -o header,看看你得到了什么。
什么应该在头文件中,什么应该在源文件中?
标题通常包含以下一项或多项:
struct、union等)另一方面,源文件有:
如何实现这种分离?
一个定义规则是你的朋友。
请记住,如果您正在编写一个库,那么这就是您的客户所看到的。因此,请提供帮助并提供所有信息,以便他们使用您的图书馆。源文件通常以二进制形式编译和提供。
顺便说一句,C 没有类的概念。
【讨论】:
struct 对我来说足够接近 :)
通常,头文件包含声明,源文件包含代码。
因此,如果在源文件 A.c 中需要在源文件 B.c 中实现的函数,则只需包含 B.h 即可获得其声明。
【讨论】:
.c 和 .h 文件之间几乎没有根本区别(尽管有些编译器可能拒绝编译原始 .h 文件)。按照惯例,差异更大。
通常,.h 文件提供 API,.c 提供实现。
因此,.h 文件将仅包含其他源文件访问 .c 文件提供的功能所需的内容。所以 .h 文件将提供全局函数的函数原型、全局变量的声明(如果你真的必须拥有它们)以及它们使用的结构和其他类型。 (如果 API 只需要指向结构的指针,则不要公开结构。)
内联函数通常也包含在 .h 文件中,但一些编码指南更喜欢使用单独的扩展名(例如 .inl)
所有其他函数实现、变量的定义和初始化以及局部(静态)变量和函数的声明都将在 .c 文件中。
【讨论】: