我们为什么不应该将定义放在标头上?

时间:2018-12-27 04:45:13

标签: c header

这是我一个人仍然无法回答的问题(可能是由于缺乏C方面的经验)。

所以我发现了这个answer,问题是将定义放入头文件有什么问题?我不是将它们声明为静态的,这应该没问题,因为它们将具有外部链接,并且链接程序也不会抱怨。

第二,为什么我们不应该将static定义放入头文件中?假设我们要使某种“编译单元私有”的功能类型不打算具有外部链接。

令我惊讶的是,为什么(很少)有可能将inline函数定义放入头文件中?

仅是按照惯例吗?

1 个答案:

答案 0 :(得分:3)

通常除非将信息包含在多个其他源文件中,否则将信息放入标头中没有任何意义。这意味着,如果标头定义了一些变量,则包含标头的每个源文件都将定义这些变量。通常,多次定义同一(全局)变量是一个错误。因此,将变量定义放在标头中通常可以消除首先创建标头的原因。

请注意,C确实有一个“单一定义规则”,类似于C ++,但没有那么强。有一个'common'扩展名-带有double entender-通常可以使您摆脱在多个文件中定义变量的麻烦,但是如果该变量具有非平凡的初始化,则不会起作用。

您可以在How do I use extern to share variables between source files?中找到很多信息,包括有关通用扩展名的信息。

通常不应在标头中定义静态变量,因为这意味着每个包含标头的文件都将定义自己的变量副本。这通常不是想要的。它倾向于使程序更大。

如果您可靠地使用支持inline的编译器,则没有特殊原因不能将static inline函数定义放入标头中。如果无法内联函数,则存在风险,编译器将在使用该函数的每个源文件的目标代码中生成静态函数,从而再次增大了可执行文件的大小。您可以通过使用非静态inline函数定义来避免这种情况。如果函数足够小以至于可以内联,则没有特殊理由不将它们放在标头中。

您可以在堆栈溢出问题中通过inlinestatic找到有关extern函数的更多信息:

请注意,以上答案中诸如“通常”和“通常”之类的狡猾的单词被大量使用。您可以小心地找到需要打破规则的特殊情况,但是如果您还记得标头是提供使用某些功能(类型,常量,函数,有时是变量)的代码与实现功能,那么您将意识到遵循以下规则是很好的:

  • 标头声明了多个源文件使用的类型,常量,枚举,函数,变量。
  • 源文件实现功能并定义多个源文件使用的变量。
  • 实现代码使用头文件来确保实现符合规范。
  • 使用者代码使用头文件来遵循实现的源代码级规则。
  • 头文件不应定义变量。
  • 源文件不应声明外部变量;它们应包含相关的标题。
  • 标题可以明智地定义static inline函数;您甚至可以在标头中包含普通的inline函数定义,但是您必须小心在没有内联的地方实例化这些函数,这就是extern inline发挥作用的时候。 (请注意,inline函数的旧GCC规则与C99标准规则不同。)

有些规则仅包含标头就不会强制执行,例如调用函数所需的顺序(例如,不要在相应的allocate函数之前调用free函数)。但是明智地使用标头可以避免很多错误。

另请参阅:

毫无疑问还有许多其他问题。