以下代码使用GCC打印出a
和b
的相同地址(未经其他编译器测试):
#include <stdio.h>
void show() {
{
static char a[0];
printf("%p\n", a);
}
{
static char b[0];
printf("%p\n", b);
}
}
int main() {
show();
}
我的问题是C标准是否允许多个变量具有相同的地址,或者这只是GCC的扩展?
答案 0 :(得分:21)
<强>约束强>
- 除了可选的类型限定符和关键字static之外,
醇>[
和]
可以分隔表达式或*。如果它们分隔表达式(指定数组的大小),则表达式应具有整数类型。如果表达式是常量表达式,它应具有大于零的值。
由于您的程序违反 (0不大于0),程序会有未定义的行为,但在这种情况下它会出现约束部分。正如4 Conformance部分所述
4符合性
在本国际标准中,“应”应被解释为实施或程序的要求;相反,''不应'被解释为禁止。
- 醇>
如果违反约束或运行时约束之外的''shall''或''shall not''要求,则行为未定义。未定义的行为在本国际标准中以“未定义的行为”或“省略行为的任何明确定义”的方式表示。这三者之间的重点没有区别;他们都描述了“未定义的行为”。
此外,5.1.1.3p1说:
- 如果预处理翻译单元或翻译单元包含违反任何语法,则符合要求的实施应至少生成一条诊断消息(以实现定义的方式标识)规则或约束,即使行为也明确指定为未定义或实现定义。在其他情况下不需要产生诊断消息。 [9])
醇>
用脚注说:
9)意图是实施应确定每次违规的性质,并在可能的情况下进行本地化。当然,只要仍然正确地翻译了有效的程序,实现就可以自由地产生任意数量的诊断。 它也可能成功翻译无效的程序。
因此
C11没有大小为0的数组。
此类数组的存在是约束违规
但是,GCC允许zero-size arrays as an extension
符合C的实施必须在此类使用时生成诊断消息。
即使设置了-std=c11
,GCC也会使用默认设置编译此默认设置而不输出诊断消息,这会使gcc -std=c11
成为不合规的实现。
[...]要获得标准所要求的所有诊断,您还应指定
-pedantic
(或-pedantic-errors
,如果您希望它们是错误而不是警告)。
因此,要使用GCC以符合C11标准的方式进行编译,必须至少明确使用gcc -std=c11 -pedantic
;然后你会得到:
zerosizearray.c:5:21: warning: ISO C forbids zero-size array ‘a’ [-Wpedantic]
static char a[0];
但是,GCC仍会编译您的程序,即使它是不正确的程序(除非您使用-pedantic-errors
);在这种情况下,自然不会适用标准的任何要求。
由于C标准实际上并不允许大小为零的对象(如果我正确读取,结构定义也必须至少有一个成员,依此类推),更重要的是,不同的对象必须占用不同的空间。对象的不同地址来自的内存;标准没有指定任何大小为0的对象的地址。
答案 1 :(得分:5)
在标准C中,不允许使用零大小的数组。
如果您使用gcc使用-pedantic
选项进行编译。它会发出警告,说:
zero.c:3:6:警告:ISO C禁止零大小数组'a'[ - &gt; pedantic]
答案 2 :(得分:3)
正如其他人已经说过的那样,标准C&C中不允许使用0长度数组。 GCC编译器允许它作为扩展。我想补充一点:您发布的程序的行为是undefined。使用%p格式说明符时,必须强制转换为void*
,因为printf
的{{1}}格式说明符需要%p
类型的参数。
请参阅此答案:printf and pointers
答案 3 :(得分:-2)
零长度数组是gcc扩展并且标准库不支持,行为取决于gcc扩展的实现
你可以在这里看到GCC文档
(?<=cn=)(?!.*cn=)([^\\]+)
被称为a zero length array