Pav*_*kin 5 c standards-compliance language-lawyer incomplete-type c11
示例代码(t0.c):
static int arr[ ];
int main( void )
{
return arr[ 0 ];
}
static int arr[ ] = { 0 };
Run Code Online (Sandbox Code Playgroud)
调用:
$ gcc t0.c -std=c11 -Wall -Wextra
<nothing>
$ clang t0.c -std=c11 -Wall -Wextra
<nothing>
$ cl t0.c /std:c11 /Za
t0.c(1): error C2133: 'arr': unknown size
$ gcc t0.c -std=c11 -Wall -Wextra -pedantic
t0.c:1:12: error: array size missing in ‘arr’
$ clang t0.c -std=c11 -Wall -Wextra -pedantic
<nothing>
Run Code Online (Sandbox Code Playgroud)
C11,6.2.5 类型,22:
未知大小的数组类型是不完整的类型。对于那种类型的标识符,通过在后面的声明中指定大小(具有内部或外部链接)来完成。
C11,6.9.2 外部对象定义,3:
如果对象的标识符声明是临时定义并具有内部链接,则声明的类型不应是不完整的类型。
C11,J.2 未定义行为,1:
具有内部链接和不完整类型的对象的标识符用暂定定义 (6.9.2) 声明。
问题:为什么一致的实现表现出不同的行为?哪一个行为正确?
根据引用的段落,特别是 6.9.2p3 和非规范性 J.2p1,很明显该代码违反了这些条款,因此可能不会出现在C 标准第 4p5 节中定义的严格一致的程序中:
严格遵守的程序应仅使用本国际标准中指定的语言和库的那些功能。它不应产生依赖于任何未指定、未定义或实现定义的行为的输出,并且不应超过任何最低实现限制
然而,实现可以自由定义严格符合程序中不允许的扩展。使用此类扩展的程序是第 4p6 节中定义的合格程序:
合规实施的两种形式是托管式和独立式。合格的托管实施应接受任何严格合格的程序。[...独立式的详细信息省略...] 一致的实现可以具有扩展(包括附加库函数),只要它们不改变任何严格一致的程序的行为
根据编译器输出,MSVC 似乎不支持此类扩展,但 gcc 和 clang 支持。
此外,当-pedantic传递标志时,gcc 会正确禁用此功能,强制严格遵守。该 clang 不会生成诊断,这-pedantic似乎是一个错误。