Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/64.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ionic-framework/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 在公共块中有全局变量是一种未定义的行为吗?_C - Fatal编程技术网

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

C 在公共块中有全局变量是一种未定义的行为吗?,c,C,0.c int i = 5; int main(){ return i; } int i; 1.c int i = 5; int main(){ return i; } int i; 上面使用gcc0.c1.c编译,没有关于多个定义的任何链接错误。原因是,i生成为公共块(-fcommon,这是gcc中的默认行为)。 正确的方法是使用此处缺少的extern关键字 我一直在网上搜索,看看这是否是未定义的行为,一些帖子说是,一些帖子说不是,这非常令人困惑: 它是UB 使用了具有

0.c

int i = 5;

int main(){
 return i;
}
int i;
1.c

int i = 5;

int main(){
 return i;
}
int i;
上面使用
gcc0.c1.c
编译,没有关于
多个定义的任何链接错误。原因是,
i
生成为
公共块(-fcommon,这是gcc中的默认行为)
。 正确的方法是使用此处缺少的
extern
关键字

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

它是UB

使用了具有外部链接的标识符,但在程序中,标识符的外部定义并不完全相同,或者未使用标识符,且标识符存在多个外部定义(6.9)

它不是UB

查找-fno common

那是哪一个呢?使用
-fcommon
是允许使用
多定义的少数几个地方之一,并且编译器会为您进行排序吗?或者它仍然是UB?

根据C标准分析代码 最新的C标准第6.9/5节对此进行了说明:

语义学

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

术语“外部定义”不应与“外部链接”或
extern
关键字混淆,它们是完全不同的概念,碰巧有相似的拼写

“外部定义”是指非暂定的定义,不在函数内部

关于暂定定义,见6.9.2/2:

对于具有文件作用域但没有初始值设定项、没有存储类说明符或具有存储类说明符static的对象,其标识符的声明构成了一个暂定定义。如果翻译单元包含一个或多个标识符的暂定定义,而翻译单元不包含该标识符的外部定义,则行为与翻译单元包含该标识符的文件范围声明完全相同,复合类型为翻译单元的末尾,初始值设定项等于
0

因此,在您的文件
1.c
中,根据6.9.2/2,该行为与它所说的
int i=0完全相同取而代之。这将是一个外部定义。这意味着
0.c
1.c
的行为就像它们有外部定义一样,违反了规则6.9/5,即外部定义不得超过一个

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

解释“未定义行为”的含义 另见:

如果不清楚,C标准中的“行为未定义”表示C标准未定义该行为。构建在不同一致性实现(或在相同一致性实现上重建)上的同一代码的行为可能不同,包括拒绝程序、接受程序或您可能想象的任何其他结果

(注意-某些程序的行为定义取决于运行时条件;这些程序不能在编译时被拒绝,除非出现导致行为未定义的条件,否则必须按照指定的方式运行。但这不适用于本问题中的程序,因为所有可能的执行都会遇到违反第6.9/5条)

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

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

J.5通用扩展插件

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

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



脚注:我有意避免在C标准未定义的行为中使用“已定义”一词,因为在我看来,这是导致OP混淆的原因之一。

这是根据标准未定义的,但在gcc中定义了实现。这不是唯一一个未定义的“起作用”的例子由于扩展。答案解释为:
…如果程序违反此规则,C标准不会定义行为(C 2018 4 2)。相反,我们让编译器和链接器定义行为。
和整个段落。尝试使用
gcc 0.c 1.c-pedantic errors-Wall-Wextra
重新编译,如果这是一个扩展,它可能会给您一个错误/警告。(尚未测试)不管它值多少钱,MSVC的link和LLVM的lld都无法链接并抛出重复的符号错误。Clang还警告说,当没有任何东西用-extern引用非静态全局变量时,会出现非静态全局变量。祝贺你提出了一个很好的问题。