为什么非 extern 可以出现在 C/C++ 中的 .h 文件中?

发布于 2024-10-25 13:00:53 字数 230 浏览 5 评论 0原文

这个文件为例,有很多非外部结构比如:

struct list_head source_list;

当这个头文件被多个编译单元包含时,它如何工作?

应该会报错同一个符号被定义了两次吧?

Take this file as example,there are many non-extern structures like:

struct list_head source_list;

How can it work when this header file is included by more than one compile units?

There should be error reporting that the same symbol is defined twice,right?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

╰つ倒转 2024-11-01 13:00:53

从技术上讲应该存在,但这种用法已经存在多年并且不可能根除(已经尝试过;每隔一段时间,一些供应商就会决定将其设为错误,并在前一百个左右的错误报告后恢复)。迂腐地,.h 文件应该声明 externone .c/.cpp 文件应该定义它。

简而言之,当您不指定顶级变量的链接(staticextern 等)时,它会被声明为“common”。在链接时,如果对该变量的所有引用都具有相同的大小(和类型,如果可用),则该变量将被分配一次,并且所有引用都将指向它。如果链接器发现同一变量有不同的大小/类型/链接,则会抛出错误。

编辑:这显然让人们感到困惑。这里:

jinx:1714 Z$ cat foo.h
int foo;
extern void bar();
jinx:1715 Z$ cat foo.c
#include "foo.h"

int
main(int argc, char **argv)
{
  bar();
  return 0;
}
jinx:1716 Z$ cat bar.c
#include "foo.h"

void
bar(void)
{
  return;
}
jinx:1717 Z$ gcc -Wall foo.c bar.c -o foo
jinx:1718 Z$ ./foo
jinx:1719 Z$ _

注意完全没有关于 int foo 被多重定义的错误。 就是我一直想说的。

Technically there should, but that usage has been around for years and is impossible to eradicate (it's been tried; every so often some vendor decides to make it an error, and reverts after the first hundred or so bug reports). Pedantically, the .h file should declare it extern and one .c/.cpp file should define it.

Briefly, when you don't specify the linkage (static, extern, etc.) of a top level variable, it's declared as "common". At link time, if all references to that variable are the same size (and type, when available) then it is allocated once and all references are made to point to it. If the linker finds different sizes / types / linkages for the same variable, it throws an error.

EDIT: this is clearly confounding people. Here:

jinx:1714 Z$ cat foo.h
int foo;
extern void bar();
jinx:1715 Z$ cat foo.c
#include "foo.h"

int
main(int argc, char **argv)
{
  bar();
  return 0;
}
jinx:1716 Z$ cat bar.c
#include "foo.h"

void
bar(void)
{
  return;
}
jinx:1717 Z$ gcc -Wall foo.c bar.c -o foo
jinx:1718 Z$ ./foo
jinx:1719 Z$ _

Note the complete lack of errors about int foo being multiply defined. This is what I've been trying to say.

活泼老夫 2024-11-01 13:00:53

这个术语是“暂定定义”:

一个标识符的声明
具有文件范围但没有
初始化器,并且没有
存储类说明符或与
存储类说明符 static,
构成一个
暂定定义。如果翻译单元包含一个或多个
暂定定义
标识符,并且翻译单元不包含外部
该标识符的定义,然后
行为就像翻译单元包含一个
文件范围声明
标识符,复合类型截至
翻译单元,带有初始化器
等于 0。

所以这在 C 中定义得很好(但经常不被接受)。

The term for this is "tentative definition":

A declaration of an identifier for an
object that has file scope without an
initializer, and without a
storage-class specifier or with the
storage-class specifier static,
constitutes a
tentative definition. If a translation unit contains one or more
tentative definitions for an
identifier, and the translation unit contains no external
definition for that identifier, then
the behavior is exactly as if the translation unit contains a
file scope declaration of that
identifier, with the composite type as of the end of the
translation unit, with an initializer
equal to 0.

So this is well defined in C (but often frowned upon).

迷雾森÷林ヴ 2024-11-01 13:00:53

此 struct list_head source_list; 字段在其他结构内声明,因此它们不是符号。

其他(顶级)结构的声明具有不同的名称,因此也可以。

编辑

请注意,此标头中的所有变量实际上都标有extern

This struct list_head source_list; fields are declared inside other structures so they are not symbols.

Declarations of other (top level) structures have distinct names so it's ok too.

edit

Note that all variables it this header are really marked with extern.

许一世地老天荒 2024-11-01 13:00:53

确实应该有一个 extern 。但是,该变量没有显式定义,因此编译器会为您将其标记为 extern。

如果您有...,您将收到链接器错误

struct list_head source_list = { 0 };

,因为每个翻译单元确实定义一次符号(因此链接器会抱怨)。

There should be an extern indeed. However, there's no explicit definition of that variable, so the compiler marks it as extern for you.

You would get a linker error if you had

struct list_head source_list = { 0 };

...since this does define the symbol once per translation unit (and hence the linker complains).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文