为什么符合要求的实现与具有内部链接的不完整数组类型的行为不同?

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) 声明。

问题:为什么一致的实现表现出不同的行为?哪一个行为正确?

dbu*_*ush 2

根据引用的段落,特别是 6.9.2p3 和非规范性 J.2p1,很明显该代码违反了这些条款,因此可能不会出现在C 标准第 4p5 节中定义的严格一致的程序中:

严格遵守的程序应仅使用本国际标准中指定的语言和库的那些功能。它不应产生依赖于任何未指定、未定义或实现定义的行为的输出,并且不应超过任何最低实现限制

然而,实现可以自由定义严格符合程序中不允许的扩展。使用此类扩展的程序是第 4p6 节中定义的合格程序:

合规实施的两种形式是托管式和独立式。合格的托管实施应接受任何严格合格的程序。[...独立式的详细信息省略...] 一致的实现可以具有扩展(包括附加库函数),只要它们不改变任何严格一致的程序的行为

根据编译器输出,MSVC 似乎不支持此类扩展,但 gcc 和 clang 支持。

此外,当-pedantic传递标志时,gcc 会正确禁用此功能,强制严格遵守。该 clang 不会生成诊断,这-pedantic似乎是一个错误。