【问题标题】:What is the fundamental difference between source and header files in C?C中源文件和头文件之间的根本区别是什么?
【发布时间】:2010-08-14 10:42:04
【问题描述】:

我不太明白应该如何在 C 的源文件和头文件中分离内容。我经常看到很多项目有两组同名文件(一个扩展名表示一个源,另一个捐赠一个头文件)。

到目前为止,由于缺乏理解,当我编写库时,我已经将所有类和类方法代码放入一个文件中,犹豫不决选择文件扩展名。

什么应该在头文件中,什么应该在源文件中?如何实现这种分离?

【问题讨论】:

    标签: c


    【解决方案1】:

    没有技术差异。编译器很乐意让您包含一个.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.cheader.h,并尝试用gcc 编译它们。 (我什至没有接近 VS!)
    • 我怀疑大多数程序员不会将静态函数的声明放在 .h 文件中。 .h 和 .c 的主要区别在于接口和实现。
    • @dirkgently:好的,但是如果您的编译器没有获得正确的文件扩展名,它就不能充当 C 编译器。该标准没有说明不是 C 编译器的程序:)
    • @Thomas:你没有正确阅读我的帖子。该标准规定了 sourceheader 文件,并没有要求对它们进行特定的扩展。是的,试试我用命令行发布的 sn-p:gcc -Wall -ansi -pedantic -std=c99 -o header,看看你得到了什么。
    • 在任何相当复杂的项目中,预编译的头文件都是必须的。如今,大多数编译器都有开关来指示要标记为预编译的特定文件。此外,它们通常需要包含在每个来​​源中。
    【解决方案2】:

    什么应该在头文件中,什么应该在源文件中?

    标题通常包含以下一项或多项:

    • 函数声明(静态除外)
    • 变量声明(通常是全局的)
    • 用户定义类型声明(阅读structunion等)
    • 宏定义

    另一方面,源文件有:

    • 函数/变量定义
    • 静态函数声明和定义(您不想将这些暴露给您的客户)
    • 变量定义
    • 有些人喜欢在标题中定义内联函数 (C99)

    如何实现这种分离?

    一个定义规则是你的朋友。

    请记住,如果您正在编写一个库,那么这就是您的客户所看到的。因此,请提供帮助并提供所有信息,以便他们使用您的图书馆。源文件通常以二进制形式编译和提供。

    顺便说一句,C 没有类的概念。

    【讨论】:

    • struct 对我来说足够接近 :)
    • 如果“单一定义规则”是金,“不要说”是银。我的意思是不要将私人细节放在头文件中。如果您制作了一个第三方库,那么您放入头文件中的所有内容将来都必须支持。如果您在大型项目中工作,最小化头文件会促进重构,因为当您确实需要更改头文件时,它将减少编译时间。 (我在一个项目中,如果你更改了中心头文件,重新编译需要 12 个小时。12hoursx#numberofdevelopers = money。)
    【解决方案3】:

    通常,头文件包含声明,源文件包含代码。

    因此,如果在源文件 A.c 中需要在源文件 B.c 中实现的函数,则只需包含 B.h 即可获得其声明。

    【讨论】:

      【解决方案4】:

      .c 和 .h 文件之间几乎没有根本区别(尽管有些编译器可能拒绝编译原始 .h 文件)。按照惯例,差异更大。

      通常,.h 文件提供 API,.c 提供实现。

      因此,.h 文件将仅包含其他源文件访问 .c 文件提供的功能所需的内容。所以 .h 文件将提供全局函数的函数原型、全局变量的声明(如果你真的必须拥有它们)以及它们使用的结构和其他类型。 (如果 API 只需要指向结构的指针,则不要公开结构。)

      内联函数通常也包含在 .h 文件中,但一些编码指南更喜欢使用单独的扩展名(例如 .inl)

      所有其他函数实现、变量的定义和初始化以及局部(静态)变量和函数的声明都将在 .c 文件中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-19
        • 2017-10-08
        • 2014-09-04
        • 2011-11-04
        • 2015-03-09
        • 2010-12-19
        相关资源
        最近更新 更多