以下示例演示了此问题:
#include <cstdio>
int main()
{
unsigned int remaining=1;
goto loop;
while(remaining) {
unsigned char tmp[remaining];
printf("&tmp: %p\n",tmp);
loop:
remaining = 512;//or something else;
}
}
最初,“剩余”变量的初始化有点长,我使用goto
在一行上初始化它。但是,现在这个例子给出了printf
行的分段错误。
看起来数组没有正确初始化。
即使gdb也无法打印tmp数组的地址:
Program received signal SIGSEGV, Segmentation fault.
0x00000000004005b8 in main () at test.cpp:11
11 printf("&tmp: %p\n",tmp);
(gdb) p tmp
$1 = 0xfffffffffffffe00 <error: Cannot access memory at address 0xfffffffffffffe00>
我的gcc版本:
gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2
编译:
g++ -o testc test.cpp
如果我删除goto,或用固定数组替换可变参数数组,则分段错误消失。 实际上发生了什么?
这是一个gcc bug吗?如果不允许goto
和可变参数数组的组合,那么应该有警告吗?
答案 0 :(得分:5)
可变长度数组( VLA )是gcc支持的C99特性an extension in C++,在C99中,跳过VLA声明是未定义的行为,来自草案C99标准部分{{ 1}} goto语句:
goto语句不得从具有标识符的范围之外跳转 在该标识符范围内的可变修改类型。
6.8.6.1
和clang
实际上是一个错误,并说:
gcc 4.9
请参阅gcc bug report: Jumps into VLA or VM scope not rejected for C++。
在{+ 1}} [stmt.dcl] 部分中介绍了跳过C ++中自动变量声明的规则:
可以转移到块中,但不能转移到块中 通过初始化绕过声明。一个跳过87的程序 具有自动存储持续时间的变量不在的点 范围到它在范围内的地方是不正确的,除非 变量具有标量类型,具有普通默认值的类类型 构造函数和一个简单的析构函数,一个cv限定版本 声明这些类型或前面类型之一的数组 没有初始化程序(8.5)。 [例如:
error: goto into protected scope goto loop; ^ note: jump bypasses initialization of variable length array unsigned char tmp[remaining]; ^
-end example]