在多个翻译单元中声明为“extern”的相同变量可以是唯一的实体吗?

问题描述 投票:0回答:1

按照C99标准:

In the set of translation units and libraries that constitutes an entire program, each
declaration of a particular identifier with external linkage denotes the same object or
function.

现在我的母语不是英语,但对我来说这本质上意味着如果我有

extern int var;
在两个翻译单元中,链接器会将它们链接在一起,以便当在任何地方定义此类时,两个声明最终都会链接到同一个对象。

如果这是真的,那么为什么如果我故意更改其中一个声明的类型,编译器/链接器不会产生类型冲突的诊断,但如果两个外部声明在同一翻译单元中声明,则会产生类型冲突的诊断?

它甚至允许我在同一个翻译单元中定义变量:

  • 图1:

extern int var;

  • 图2:

extern float var;
float var = 2.5;

但是如果我也在 TU1 中定义 var,链接器基本上会崩溃,而不会再次提供任何诊断。编译标志是:

-Wall -Wextra -pedantic -Werror=shadow -std=c99

我的问题可以通过问为什么 GCC 会有这样的行为(两次都误诊)以及对于这样的代码理想的、符合标准的处理方式应该是什么来结束?

gcc linker declaration extern
1个回答
0
投票

为什么如果我故意更改其中一个声明的类型,编译器/链接器不会生成类型冲突的诊断,

链接时符号类型会丢失。链接器只能看到符号的名称。并匹配名称。

为什么

现在已经2022年了。引入 LTO 和 C++ 模块是有原因的。 C 是一门有 50 年历史的语言。当 C 编程语言和链接器被发明来让它了解符号类型时,没有足够的计算机能力和人力。

请注意,您正在阅读的文档并不“需要”诊断,以防违反此规则。如果规则被打破,你会得到“未定义的行为”。未定义的行为意味着对将会发生的事情没有任何要求,你可能会得到诊断,或者产生鼻恶魔。您不能“期待”诊断。 另请注意,您正在阅读 C99,它已经有 20 年历史了。考虑 C11 或 C23。

如果两个外部声明在同一个翻译单元中声明,它会这样做吗?

因为

编译器

在编译时会看到整个翻译单元,它会看到符号冲突并且
能够

对此进行说明。或者换句话说,因为5.1.1.3p1要求在这种情况下发出诊断。 对于这样的代码,理想的、符合标准的处理应该是什么?

完全忽略这种情况。假设它永远不会发生。

事实恰恰相反。需要符合标准的编译器来编译符合标准的程序。对任何其他程序的编译结果没有要求。如果您将具有未定义行为的程序提供给任何符合标准的编译器,则任何事情都可以发生。编译器可能会假设程序员永远不会编写具有未定义行为的程序,因此他们可以完全忽略这种情况将会发生。程序员写了无效的程序,这是程序员的错,程序员应该修复它。

© www.soinside.com 2019 - 2024. All rights reserved.