【问题标题】:Define a function before main?在main之前定义一个函数?
【发布时间】:2010-11-04 11:47:31
【问题描述】:

C99 中是否需要函数声明/原型?

我目前正在头文件中定义我的函数,并在主文件中#include-ING 它。这在 C99 中可以吗?

为什么大多数程序员在 main() 之前声明/原型函数并在 main() 之后定义它?在 main 之前定义它们并避免所有声明/原型不是更容易吗?

header.h 文件内容:

int foo(int foo)
{
// code
return 1;
}

主文件内容:

#include <stdio.h>

#include "header.h"

int main(void)
{
foo(1);
return 0;
}

【问题讨论】:

    标签: c c99


    【解决方案1】:

    在 C 中如何以及在何处对函数进行原型设计和定义:

    1. 您的函数仅在特定的 .c 文件中使用: 在 .c 文件中将其定义为静态。该函数将仅对此文件可见和编译。

    2. 您的函数在多个 .c 文件中使用: 选择一个合适的 c 文件来托管您的定义(例如 foo.c 文件中的所有与 foo 相关的函数),并有一个相关的头文件来对所有非静态(认为公共)函数进行原型化。该函数将只编译一次,但对包含头文件的任何文件都是可见的。一切都将在链接时放在一起。可能的改进:总是将相关的头文件,第一个包含在其c文件中,这样,您将确保任何文件都可以安全地包含它而无需其他包含使其工作,参考:Large Scale C++ projects(大多数规则也适用于 C)。

    3. 您的函数是可内联的(您确定是吗?): 在适当的头文件中定义函数静态内联。如果可能的话,编译器应该用定义替换对你的函数的任何调用(想想宏)。

    c 中的前后另一个函数(您的主函数)的概念只是风格问题。要么你做:

    static int foo(int foo) 
    { 
    // code 
    return 1; 
    } 
    
    int main(void) 
    { 
    foo(1); 
    return 0; 
    } 
    

    或者

    static int foo(int foo);
    
    int main(void) 
    { 
    foo(1); 
    return 0; 
    } 
    
    static int foo(int foo)
    { 
    // code 
    return 1; 
    } 
    

    将产生相同的程序。程序员更喜欢第二种方式,因为您不必在每次声明使用其他函数的新函数时重新组织或声明新原型。此外,您还可以获得文件中声明的每个函数的漂亮列表。从长远来看,它会让您和您的团队生活更轻松。

    【讨论】:

    • 我可以把static foo的声明放在.h文件里,定义放在.c文件里吗?
    • @Alcott :不,我认为你会得到一个错误:“'foo' 声明为'静态'但从未定义”对于每个包含你的标题的文件。将静态视为“本地”。向所有人宣传(放在头文件中)本地的东西是没有意义的,除非您将其提供给所有人的本地副本(内联)。
    【解决方案2】:

    人们通常这样做是因为处理多个文件更容易。如果您在标头中声明,那么您可以在需要这些功能的任何地方#include 该标头。如果您在标题中定义它们,然后包含在另一个翻译单元中,砰。

    【讨论】:

    • 但是使用(监视)狗和静态函数可以轻松地保护您免受爆炸。您甚至可能想在标题中定义函数。你为什么要这样做,听起来很危险(它是)?大多数编译器会更好地优化静态函数的代码。如果您不一路走下去,成本就是编译时间和一些代码重复(在标题中定义程序的all)。我目前正在使用这种风格编写一个大约 40000 行的 C++ 程序,对我来说效果很好。
    【解决方案3】:

    函数 声明 在 C99 中是必需的。 C99 中不需要函数原型

    在调用点之前声明函数并在调用点之后定义它们是构建程序代码的一种流行方法。然而,这绝不是“大多数”程序员所做的。相反,更流行的方法是在第一次调用之前定义函数,在这种情况下,不需要单独声明。这种方法需要较少的维护,这就是它比您描述的更受欢迎的原因。

    单独的声明/定义通常仅与外部函数一起使用,即与跨多个翻译单元使用的函数一起使用。此类函数在头文件中声明并在实现文件中定义。

    【讨论】:

      【解决方案4】:

      您应该只在标题中定义inline 函数。虽然您可以拥有extern inline 函数,但常见的情况是static inline

      头文件的经验法则:

      • 函数声明应该是extern
      • 函数定义应该是static inline
      • 变量声明应该是extern
      • 变量定义应该是static const

      正如 C. Ross 所要求的,其背后的原因如下:具有外部链接的资源只能被定义一次[1]。因此,定义不应驻留在头文件中,这些头文件旨在包含在多个位置。

      在头文件中有static 定义不会导致任何问题,但通常不被接受,因为代码必须编译多次并且会出现在不同的目标文件中,这会增加可执行文件的大小(假设链接器不够聪明,无法找出代码重复)。

      此规则的常见例外是常量和inline 函数,它们应该对每个翻译单元中的编译器可见,以便进一步优化。

      注意: [1] 这不适用于具有外部链接的 inline 函数,但由于未指定内联函数的多个定义中的哪一个将用于函数的评估指示符,它们大多没用

      【讨论】:

      • 是的,但你没有说为什么
      • 赞成,但我仍有 2 个问题。 1、如果我想在程序中使用static void foo(),我应该把foo的声明放在程序的.h文件还是.c文件中?我问这个问题是因为我很困惑,.h 文件是否应该只包含可以被多个.c 文件访问的extern 函数,而不仅仅是一个? 2、我了解到,inline函数应该定义在.h文件中,那为什么要使用static inline呢? static 是否意味着内联函数只能在一个 .c 文件中可见?
      【解决方案5】:

      您的方法适用于小型程序。头文件用于声明和常量定义——它们为它们“封装”的程序提供接口。标头是其他程序单元的接口。

      如果你有更多的 .c 文件,前向声明和头文件是必要的,因为一个 C 函数只能为整个程序定义一次(搜索一个定义规则),即使你可以在任何地方使用该函数(在任何 .c 文件中)。如果您在标头中定义它,它将包含在您使用它的所有 .c 文件中并导致多个定义。

      【讨论】:

      • 即使对于小程序,我也不建议在头文件中定义非内联函数。这是一个坏习惯。
      • @Matthieu:当某事是好的时,不清楚做完全相反的事情也不好。正如我在对 DeadMG 答案的评论中所说,我确实在标头中定义函数,不是作为一种习惯,而是作为一种优化技巧和一种编程风格。与 BOOST 大量使用的 C++ 的“仅标头”类的想法相同。如果 C 或 C++ 像其他语言一样有一个编译器(在链接之前)可以理解的模块概念,而不是这些血腥的文本级别包含,那么它可能是无用的。
      • @kriss :它在 C++ 中是有意义的,尤其是在模板/元编程的约束下(即使你必须考虑编译时间成本),但我看不出有什么好处C 中的标头定义,内联除外。我同意头文件结构是 c/c++ 的“弱点”。
      【解决方案6】:

      这样比较快,不过我个人更喜欢把main函数放在main文件的开头,其他函数放在其他文件或者main下面。

      请注意,在您的示例中,您应该避免在头文件中声明 foo():您将无法将其包含在两个不同的源文件中。在包含 main() 的 C 文件中声明它;除非您从其他文件中引用它,否则您不需要在其他地方定义它。

      【讨论】:

        【解决方案7】:

        是的,在 main 之前定义它们更容易。如果您只想在文件中使用这些函数,则不需要原型。但是,在这种情况下,您也可以在函数定义之前添加“静态”关键字。 (在 C 文件中。)这将确保该函数对其他文件不可见。 (在链接时。)

        不要将静态关键字放在包含文件中。

        【讨论】:

        • 但是如果在头文件中声明为static,那么每个包含这个头文件的c文件都会有自己的函数,除非函数是内联的,否则这不是一个理想的结果。
        • @Matthieu,嗯,我不是这个意思。
        • @Matthieu:如果你使用经典的 C 编程风格,静态函数根本不应该出现在标题中。
        【解决方案8】:

        你应该总是原型。

        原因是:

        1. 方法原型在代码中函数的头文件中生成一个简洁的列表 - 这对未来的读者来说非常宝贵

        2. 除了最简单的项目外,许多函数在 main 之前是不可见的。

        3. main 应该是其文件中的第一个函数;这对读者来说更容易,因为我们是向下而不是向上阅读

        【讨论】:

        • 1,包含文件用于应该导出到文件之外的函数,恕我直言。 2,我不知道这意味着什么...... 3,或者包含 main() 的文件可能应该没有或很少有其他功能,比如信号处理程序。
        • 当我写库时,那里的C文件有一个H文件,它是库内部的;包含原型(如果所有 C 文件都合并为一个,那么原型将是静态的)。其中包含库私有函数的列表。关于包含 main 的文件,我完全同意。
        【解决方案9】:

        为什么大多数程序员在 main() 之前声明/原型函数并在 main() 之后定义它?

        仅仅是因为大多数人是按顺序阅读的。从头开始一个故事,而不是从中间开始。没必要,直观即可。

        当然,如果被原型化的代码在一个单独的编译单元中,那么原型是必要的

        【讨论】:

          【解决方案10】:

          在 main 之前或在单独的头文件中声明函数始终是一个好习惯,该头文件将包含在我们使用该函数的其他 c 文件中。通过这样做,我们可以轻松识别 .C 或 .H 文件中声明/定义的所有函数。在头文件中声明函数之前,我们应该使用 extern 关键字。

          【讨论】:

            猜你喜欢
            • 2012-06-09
            • 2011-11-28
            • 1970-01-01
            • 2014-05-21
            • 1970-01-01
            • 2017-08-26
            • 2011-06-20
            • 1970-01-01
            • 2011-07-10
            相关资源
            最近更新 更多