【问题标题】:Functions in C Headers?C 头文件中的函数?
【发布时间】:2018-05-17 19:23:48
【问题描述】:

我听说您将函数原型放在头文件中,然后将函数定义放在 .c 文件中。但是,这个 .c 文件是什么。例如,如果你要包含一个文件“foo.h”,你会不会调用前面提到的.c文件“foo.c”,把函数定义放在里面,把它和foo.h放在同一个地方,然后当您尝试包含 foo.h 时,该函数是否会从 c 文件中继承,并且该函数是否可以使用?

【问题讨论】:

  • 函数不放在头文件中的原因是,如果你把它包含在两个.c文件中,你会得到两个函数的定义。

标签: c function header


【解决方案1】:

不,只需将.c.h 放在一起并将其包含在您的代码中也不会神奇地继承函数的定义。

您需要将foo.c单独编译成一个目标文件(在Linux的情况下,它是一个.o文件)。例如使用命令 -

gcc -c foo.c -o foo.o

现在这个foo.o 需要链接到您的实际程序。这可以通过在编译为

时简单地传递目标文件来完成
gcc test.c foo.o -o test.out

如果您没有将foo.o 与您的程序链接,您的链接器将无法找到其中定义的函数的实现,并将引发链接器错误 -

对函数foo_function的未定义引用。

【讨论】:

  • 感谢您的帮助!还有一个问题:在 foo.c 中,是否必须包含 foo.h,还是只定义函数而不提及标头?
  • @J.S.通常最好在相应的.c 中包含标头,以便标头中的类型与定义中的类型相匹配。如果误认为不同,编译器会报错。
  • 好的,感谢您的帮助,非常感谢 :)
  • @J.S.我会比“通常是个好主意”更进一步,然后说,“是的,你必须这样做”。没有它它也能工作,这是真的,但它在类型检查系统中打开了一个巨大的漏洞。 (我,我希望编译器会抱怨在范围内没有原型的情况下定义函数,就像他们抱怨在范围内没有原型的情况下调用函数一样。)
  • 现代 GCC 确实抱怨更多关于在范围内没有声明的函数调用 - GCC 编译器版本 5.0 及更高版本默认使用 C11 模式。他们仍然不会自动抱怨没有原型;您可以使用-Wstrict-prototypes 启用它(这不是-Wall-Wextra 的一部分,令我大吃一惊)。还有-Wold-style-definition-Wold-style-declaration-Wmissing-prototypes
【解决方案2】:

头文件只是常规的。 C preprocessor 正在处理 #include directives 并且编译器会看到预处理的输入(但您可能会复制并粘贴大量 C 代码以获得等效于 #include 的代码)。实际上,预处理器不在乎你是#include "foo.h" 还是#include "foo.c",但后者往往味道很差。使用.h 后缀命名头文件只是一个(非常常见的)约定

因此,如果您在多个源文件(技术上为 translation units)的标头中包含函数定义,则该函数定义在每个此类翻译单元中。

然后会发生什么取决于该函数定义(应该是 static 或更好的 static inline)。

实际上,您应该将标头中的函数定义限制为staticstatic inline。如果您没有在包含在多个*.c 文件中的标头中声明static 函数定义void foo(int x) { /* something */ },您将在link 时间出现foo 的多个定义错误。将函数定义放在标头中的主要目的是启用内联(因此inline 提示);否则(通常情况下),您不需要它,只需将函数原型放在头文件中,并将函数定义放在 *.c 文件的 one 中。

如果你有简短而快速的运行函数,明智的做法是在你的头文件中定义它们为static inline(所以给出它们的主体)(当然,这会增加编译时间)。否则,这负担不值得。

一些头文件可能有很长的宏(有几十个物理行,除了最后一个以反斜杠结尾之外的所有行)扩展为函数定义。以sglib 为例。

请注意,inline 在今天(就像 register 在过去十年中一样)只是对编译器的提示(用于inline expansion 优化),允许忽略它(也, 许多optimizing compilers 能够在没有任何注释的情况下内联函数,只要他们知道被调用函数的主体)。

不要忘记启用所有警告和调试信息。 With GCC,使用 gcc -Wall -Wextra -g,也许与 -Wstrict-prototypes 一起使用。您可以使用-H 获取包含的文件(以及使用-C -E 的预处理表单)。

有关详细信息,请参阅某些 C reference 站点和 C11 标准 n1570。阅读GNU cpp reference 手册了解预处理。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-22
    • 2013-03-15
    • 2022-01-09
    • 2020-10-03
    • 2016-03-12
    相关资源
    最近更新 更多