3

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

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

b.c 
----
extern int x;

==>检查补丁抱怨

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

a.c
----
int x;

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

==> 不抱怨

我想了解为什么这更好

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

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

4

6 回答 6

3

将 ah 也包含在 ac 文件中会更好。这样,编译器可以验证声明和定义是否相互匹配。

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无论如何都不会是头文件中的唯一元素,因此您不会节省文件数。

于 2013-02-08T12:13:28.437 回答
1

我看到两个原因:

  1. 如果你共享一个变量,那是因为它不在你自己的文件中,所以你想通过将它添加到头文件来明确它是共享的extern- 这样,只有一个地方[包含目录]可以搜索extern声明.
  2. 它避免了某人做出extern声明,然后其他人为同一事物做出不同的(如使用不同的类型或属性)extern 声明。至少如果它在头文件中[相关],所有文件都使用相同的声明。
  3. 如果您决定更改类型,则只有两个地方可以更改。如果您要添加一个也使用相同变量的“cc”文件,然后认为这int还不够好,我需要long,您必须修改所有三个位置,而不是像有包含在“ac”、“bc”和“cc”中的每个头文件。

为您的模块提供头文件绝对不是一个坏主意。但这当然是可以接受的,这取决于将其extern放入某些现有头文件的情况。

另一种选择(通常比使用 extern 更好)是使用 ,getter function为您获取变量。这样,变量可以在其自己的源文件中是静态的[没有“命名空间污染”,并且变量的类型也定义得更好——编译器可以检测你是否试图错误地使用它。

编辑:我应该指出,Linux 编码风格是出于“好的”原因而采用的方式,但这并不意味着不属于 Linux 源代码的代码不能以各种方式破坏这些规则。我当然不会使用 Linux 的格式编写自己的代码——我更喜欢{ }单个语句,而且我(几乎)总是{换行,与大括号所属的任何内容一致,并且}再次在同一列中.

于 2013-02-08T12:06:14.677 回答
0

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

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

于 2013-02-08T11:49:03.793 回答
0

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

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

然后习惯它。这是一个合乎逻辑的概念,也是适应的好习惯

于 2013-02-08T11:56:04.763 回答
0

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

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

于 2013-02-08T11:57:08.600 回答
0

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

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

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

于 2013-02-08T15:21:21.660 回答