为什么extern声明应该在.c文件之外(根据linux编码风格)

时间:2013-02-08 11:38:47

标签: c linux coding-style linux-kernel extern

根据checkpatch.pl脚本“extern声明在.c文件之外” (用于检查补丁是否符合编码风格) 注意:如果没有编译警告,这完全正常 通过在.h文件中放置extern声明来解决该问题。

a.c
-----
int x;
...

b.c 
----
extern int x;

==> checkpatch抱怨

a.h
-----
extern int x;

a.c
----
int x;

b.c
---- 
#include "a.h"

==>不抱怨

我想了解为什么这样更好

我的推测。 理想情况下,代码被拆分为文件,以便模块化代码(每个文件都是一个模块) 模块导出的接口放在头文件中,以便其他模块(或.c文件)可以包含它们。因此,如果任何模块想要在外部公开一些变量,那么必须在与模块对应的Header文件中添加extern声明。

同样,拥有与每个模块(.c文件)对应的头文件似乎 许多头文件。

6 个答案:

答案 0 :(得分:3)

将a.h包含在a.c文件中会更好。这样编译器就可以验证声明和定义是否相互匹配。

a.h
-----
extern int x;

a.c
----
#include "a.h"  <<--- add this
int x;

b.c
---- 
#include "a.h"

正如您所假设的那样,规则的原因是我们应该使用编译器来检查我们正在做什么。微小的细节会好得多。

如果我们允许在整个地方进行外部声明,如果我们想要将x更改为其他类型,我们会遇到麻烦。我们需要扫描多少.c文件才能找到所有extern int x?许多。如果我们这样做,我们可能会发现一些extern char x错误。糟糕!

只需在头文件中包含一个声明,并将其包含在需要的地方,就可以省去很多麻烦。在任何实际项目中,x都不会是头文件中的唯一元素,因此您无法保存文件数。

答案 1 :(得分:1)

我认为有两个原因:

  1. 如果您共享一个变量,那是因为它不在您自己的文件中,所以您希望通过将extern添加到头文件来明确它是共享的 - 这样,只有一个地方[ include目录]来搜索extern声明。
  2. 它避免某人发出extern声明,然后其他人为同一事物做出不同的(如使用不同的类型或属性)extern声明。至少如果它在头文件中[相关],则所有文件都使用相同的声明。
  3. 如果您决定更改类型,则只需更改两个位置。如果您要添加也使用相同变量的“cc”文件,然后确定int不够好,我需要long,您必须修改所有三个地方,而不是如果每个“ac”,“bc”和“cc”中都包含一个头文件,那么就会超过两个。
  4. 拥有模块的头文件绝对不是一个坏主意。但它当然可以接受,具体取决于将extern放入某些现有头文件的情况。

    另一种选择,通常是比使用extern更好的选择,就是拥有一个getter function,为您提取变量。这样,变量在其自己的源文件中可以是静态的[没有“命名空间污染”,并且变量的类型也更加明确 - 编译器可以检测您是否正在尝试错误地使用它。

    编辑:我应该指出Linux编码风格是出于“好”的原因,但这并不意味着不属于Linux源代码的代码不能破坏各种规则方法。我当然不会使用Linux的格式编写我自己的代码 - 我喜欢在单个语句周围添加{ },而且我(几乎)总是将{放在一个新行上,与任何大括号一致属于,}再次出现在同一列中。

答案 2 :(得分:0)

我总是在.h中放置extern声明的一个原因是为了防止代码重复,特别是如果有或者可能有更多的代码使用你的“a.c”代码并且必须访问“x”。在这种情况下,所有文件都必须具有extern声明。

另一个原因是extern声明是模块接口的一部分,因此我会将它与头文件中的任何其他接口信息一起保留。

答案 3 :(得分:0)

您的推测是正确的:为了最大限度地重用代码和一致性,必须将(公共)声明放入头文件中。

  

同样,拥有与每个模块(.c文件)对应的头文件似乎有许多头文件。

然后习惯它。这是一个合乎逻辑的概念和适应性的良好实践

答案 4 :(得分:0)

你有理由说明为什么必须将extern声明放在头文件中。因此,可以轻松地跨不同的翻译单元访问它们。

此外,每个.c文件都不必具有相应的.h文件。一个.h文件可以对应于相当数量的.c文件,具体取决于您的模块隔离设计。

答案 5 :(得分:0)

  

同样,拥有与每个模块(.c文件)对应的头文件似乎要有许多头文件。

正如您所说,头文件的想法很简单。它们包含模块要将其导出(可用)到其他模块(包含在其他.c文件中)的公共接口。这可以包括结构和类型以及函数声明。现在,如果一个模块定义了一个它想要提供给其他模块的变量,那么将它包含在头文件中的其他公共部分是有意义的。这就是externs最终在头文件中的原因。它们只是该模块想要公开的事物的一部分。然后任何人都可以通过简单地包含头文件来包含这个公共接口。

每个.c文件都有一个.h文件可能看起来很多,但这可能是正确的做法。但请记住,模块可以在多个.c文件中实现其代码,并选择将其聚合公共接口导出到单个.h文件中。所以,它并不是一对一的严格。真正的抽象是模块提供的公共接口。