在公共块中具有全局变量是一种未定义的行为

  • 本文关键字:一种 未定义 全局变量 c
  • 更新时间 :
  • 英文 :


0.c

int i = 5;
int main(){
return i;
}

1.c

int i;

上面用gcc 0.c 1.c编译得很好,没有任何关于multiple definitions的链接错误。原因是i被生成为common blocks (-fcommon which is the default behaviour in gcc)。正确的方法是使用此处缺少的extern关键字。

我一直在网上搜索,看看这是否是未定义的行为,一些帖子说是,有些帖子说不是,这非常令人困惑:

是UB

在单独的文件中有多个临时定义是未定义的行为吗?

为什么我可以在C中定义一个变量两次?

如何使用extern在源文件之间共享变量?

http://port70.net/~nsz/c/c11/n1570.html#J.2

使用了具有外部链接的标识符,但在程序中,该标识符不存在一个确切的外部定义,或者该标识符没有使用,并且存在多个标识符的外部定义(6.9)

它不是UB

全局变量和.data部分

在C 中的多个文件中定义外部变量

C和C++一样有一个定义规则吗?

Look for -fno-common:https://gcc.gnu.org/onlinedocs/gcc-4.8.5/gcc/Code-Gen-Options.html

那是哪一个呢?使用-fcommon是为数不多的允许使用multiple definition的地方之一,编译器会为您进行排序吗?还是还是UB?

根据C标准分析代码

这包含在最新的C标准:的第6.9/5节中

语义

外部定义是一种外部声明,也是函数(内联定义除外)或对象的定义。如果在表达式中使用了用外部链接声明的标识符(而不是作为结果为整数常量的sizeof_Alignof运算符的操作数的一部分),则在整个程序的某个地方标识符;否则,不得超过一个。

术语";外部定义";不应与";"外部链接";或者extern关键字,这些都是完全不同的概念,恰好具有相似的拼写。

"外部定义";指不是暂定的定义,也不在函数内部。

关于暂定定义,其内容见6.9.2/2:

一个对象的标识符声明,该对象具有文件作用域,没有初始值设定项,没有存储类说明符或具有存储类说明符static,构成临时定义。如果一个翻译单元包含一个或多个标识符的临时定义,而该翻译单元不包含该标识符的外部定义

因此,在您的文件1.c中,根据6.9.2/2,行为与它所说的int i = 0;完全相同。这将是一个外部定义。这意味着0.c1.c都表现得好像它们有外部定义,这违反了规则6.9/5,即不应有一个以上的外部定义。

违反语义规则意味着行为未定义,不需要诊断

解释什么";未定义行为";手段

另请参阅:未定义、未指定和实现定义的行为

在不清楚的情况下,C标准说";行为是未定义的";意味着C标准没有定义行为。在不同的一致性实现上构建的相同代码(或在相同的一致性实施上重建的代码)可能会有不同的行为,包括拒绝程序、接受程序或您可能想象的任何其他结果。

(注意-一些程序的行为可以根据运行时条件进行定义;这些程序在编译时不能被拒绝,并且必须按照指定的方式运行,除非出现导致行为未定义的条件。但这不适用于这个问题中的程序,因为所有可能的执行都会遇到违反6.9/5的情况)

编译器供应商可能会也可能不会为C标准未定义行为的情况提供稳定和/或记录的行为

对于您问题中的代码,编译器供应商提供可靠行为是很常见的(哈哈);这记录在标准的非规范性附录J.5.11:中

J.5常见扩展

J.5.11多种外部定义1对象的标识符可能有多个外部定义,无论是否明确使用关键字extern;如果定义不一致,或者初始化了多个,则行为未定义(6.9.2)。

如果提供了-fcommon开关,gcc编译器似乎会实现此扩展,如果提供-fno-common,则会禁用它(默认设置可能因编译器版本而异)。


脚注:我有意避免使用";定义的";与C标准未定义的行为有关,在我看来,这是造成OP混乱的原因之一。

相关内容

最新更新