何时将静态函数定义放在C中的头文件中?

hor*_*guy 26 c static header code-organization

我遇到了一些在头文件中有一个大的静态函数的代码,我只是好奇它是不是可以做到这一点.例如,如果许多.c文件包含标题,为什么不直接定义非静态函数并将其链接?

关于何时/何时不将静态函数定义放在C中的头文件中的任何建议或经验法则,我们将不胜感激,

谢谢

R..*_*R.. 26

一些想法:

  • 我能想到的一个可能的合法用途是,当你想要创建一个函数而不创建带有外部链接的符号并污染外部命名空间时.(但是你可以使用一个模糊的前缀名称,例如mylib123__foobar,#define foobar mylib123__foobar在头文件中,所以这个看起来有点不确定.)
  • 您希望某些功能仅通过头文件可用,而无需用户链接库/目标文件.我可以看到这是一个真正的动机,提供一个几乎只有数据结构和操作它们的一些琐碎代码的"库".事实上,如果数据结构不是不透明的并且意图由应用程序直接访问,那么将函数与它们一起使用在同一个头文件中(而不是在库中)可以大大降低在更改数据时破坏事物的风险结构.
  • 也许该函数仅仅是外部函数的包装器,并且包装器的工作方式可能取决于调用编译单元中的编译时选项.例如:

    static int foobar(int x)
    {
        return real_foobar(COMPILETIME_PARAMETER, x);
    }
    
    Run Code Online (Sandbox Code Playgroud)

    您可能会说只使用宏,但是如果foobar需要通过函数指针调用预期用途呢?

有了这个说过......

实际上,人们将static函数放在头文件中的主要原因通常是基于一些10年过时的概念,它会通过允许编译器内联函数或诸如此类来提高性能.大多数这样做的人都没有做过任何测量.由于现代编译器可以将整个程序编译为一个单元,如果被问到,这在理论上会导致更多的优化可能性,并且因为它开始时是一个值得怀疑的优化,所以我真的对为了性能目的而在函数头中放置函数持怀疑态度.

这种批评特别适用于OP在头文件中的"大"静态函数的例子.除非常量参数值允许编译器消除90%的代码或其他内容,否则大型函数几乎不可能从内联中受益.(有关这种极端情况的真实示例,请参阅libavcodec.:-)中使用的一些疯狂的内联函数/宏定义.:-)


Jan*_*der 9

根据经验,您不应该在头文件中放置静态函数.在一次性程序中,除了扩展代码的大小之外,它可能不会伤害任何东西,因为你在每个模块中都有一个冗余副本.在共享库中,它很容易导致错误,因为现在您的库的一部分嵌入在库的调用者中,因此很容易发生版本不匹配.

如果你有一些非常可怕的时间关键函数,其中使函数调用花费的时间很重要,你可以考虑将它放在标题中,但在这种情况下(a)你可能也想要将它声明为内联函数,并且(b)您已经完成了可以找到的所有其他优化.

简而言之,除非你知道在头文件中需要静态函数,否则你不需要在头文件中使用静态函数; 你想要一个.c文件中的非静态函数,其标题在.h中.


tob*_*ies 9

根据我的经验,在.h文件中定义一个函数通常是一个坏主意,而且我从来没有理由这样做,偶然这样做会导致我头疼不已.

虽然我猜它会允许包含标题的每个文件都有自己独立的函数实现,如果函数有静态变量,可能是所需的行为,例如,如果你想/需要分别跟踪每个信息的某些信息文件.

  • 我认为你的第二段是正确的.我同意如果你可以使函数重入(例如通过分配然后传入指向状态结构的指针),那将是一个更好的解决方案. (3认同)

Jen*_*edt 5

现代 C 已经采用了inlineC++ 中的关键字来完成这样的任务。但是如果你的编译器static在头文件中没有(还没有?)是一种模拟它的方法。inline并不意味着该函数必须内联到任何调用者,而只是在最终的可执行文件中通常最多只有一个副本。(从技术上讲,相应的链接器符号是“弱”符号。)相反,如果只是声明static每个编译单元将保留一个副本。

这种在头文件中定义函数的方法应该仅限于执行小任务的函数,如果将代码优化到调用函数中,编译器可能会大幅改进代码。

这样做时,还要注意这些功能的实现。您可能会因此而打破将声明包含到 C++ 中的可能性。通常这两种语言只(大部分)在接口上达成一致,不一定在实现上达成一致,存在细微差别。