C11下内部链接不完整非数组类型试探性定义的合规行为判定
问题结论
根据C11标准规定,MSVC(cl)和clang的行为符合规范,GCC与ICC(英特尔编译器)的行为不符合规范。
背景
当具有内部链接的变量的试探性定义为不完整非数组类型时,不同合规编译器实现表现出差异化行为。
示例代码(t940.c)
static struct s foo; static struct s {int a;} foo;
各编译器编译结果
- gcc 11.2.0:编译无任何输出,无诊断信息
编译命令:gcc t940.c -c -std=c11 -pedantic -Wall -Wextra -Wno-unused-variable - clang 13.0.0:编译输出1条警告
编译命令:clang t940.c -c -std=c11 -pedantic -Wall -Wextra -Wno-unused-variable
警告内容:t940.c:1:17: warning: tentative definition of variable with internal linkage has incomplete non-array type 'struct s' [-Wtentative-definition-incomplete-type] static struct s foo; ^ t940.c:1:15: note: forward declaration of 'struct s' static struct s foo; ^ 1 warning generated. - cl 19.29.30133:编译报错终止
编译命令:cl t940.c /c /std:c11 /Za
错误内容:Microsoft (R) C/C++ Optimizing Compiler Version 19.29.30133 for x64 Copyright (C) Microsoft Corporation. All rights reserved. t940.c t940.c(1): error C2079: 'foo' uses undefined struct 's' t940.c(2): error C2371: 'foo': redefinition; different basic types t940.c(1): note: see declaration of 'foo' - icc 2021.1.2:编译无任何输出,无诊断信息
编译命令:icl t940.c -c -std=c11 -pedantic -Wno-unused-variable
标准依据解释
C11标准有明确约束:
- 6.7节第3条规定:对象的声明如果不是外部定义,不能声明为不完整类型。示例第一行的
static struct s foo属于对象声明,此时struct s尚未完成定义,属于不完整类型,已经违反约束,编译器必须给出诊断信息。 - 6.9.2节关于试探性定义的补充规则也明确:如果具有内部链接的试探性定义到翻译单元末尾仍为不完整类型,程序属于未定义行为,且编译器必须对违反约束的情况给出诊断。
- 标准仅要求编译器对约束违反给出诊断,警告属于合法的诊断形式,因此clang输出警告符合要求,MSVC选择升级为错误终止编译也符合要求,只有未给出任何诊断的GCC和ICC属于违规。
内容的提问来源于stack exchange,提问作者pmor
相关产品推荐
相关产品推荐

