假设这些代码在编译g++
:
#include <stdlib.h>
int main() {
int a =0;
goto exit;
int *b = NULL;
exit:
return 0;
}
g++
会抛出错误:
goto_test.c:10:1: error: jump to label ‘exit’ [-fpermissive]
goto_test.c:6:10: error: from here [-fpermissive]
goto_test.c:8:10: error: crosses initialization of ‘int* b’
好像是, goto
不能跨越指针的定义,但gcc
编译他们OK,没有什么抱怨。
固定的错误后,我们必须在任何的声明所有的指针goto
声明,也就是说,即使你没有在本(和侵犯一些原则),需要他们必须声明这些指针。
什么是原点设计考虑到g++
禁止有用尾goto语句?
更新:
goto
可以跨越变量( 任何类型的变量,不限于指针)声明, 但除了那些有一个初始化值 。 如果我们去掉NULL
上述分配, g++
现在保持沉默。 所以,如果你想声明的变量之间goto
-Cross区域, 不要初始化它们(和仍然违反了一些原则)。
转到不能跳过的变量初始化,因为被执行初始化时就不会在跳转后有相应的对象,因为用不平凡的开始初始化对象的生命周期:
C ++ 11§3.8/ 1:
[...] T类型的对象的生存期开始时:
获得具有对于类型T的适当对准和尺寸存储,并
如果对象具有不平凡的初始化,初始化完成。
C ++ 11§6.7/ 3:
有可能转移到块,但不是在绕过声明与初始化的方法。 从一个点,具有自动存储持续时间的变量不是在范围上的点是在范围上跳跃的程序是非法的构造,除非变量具有标量类型,类型与平凡缺省构造和一个微不足道的析构函数,一个和这些类型之一的CV-合格版本,或前述类型之一的阵列被声明没有初始化(8.5)。
由于错误中提到[-fpermissive]
您可以通过指定编译器标志把它转化为警告。 这说明了两两件事。 它曾经是允许的(变量会存在,但跳转后未初始化)和GCC开发者认为,规范禁止它。
编译器只检查变量是否应该被初始化,而不是是否它的使用,否则效果会相当不一致。 但是,如果你不需要的变量了,你可以结束它自己的生命周期,使得“尾转到”可行的:
int main() {
int a =0;
goto exit;
{
int *b = NULL;
}
exit:
return 0;
}
是完全有效的。
在一个侧面说明,该文件有扩展.c
,这表明它是C,而不是C ++。 如果你有编译gcc
,而不是g++
,原来的版本应该编译,因为C没有这个限制(只对变长数组,不C ++中存在的所有限制)。
有一个简单的工作环境对于那些原始的类型,如int
:
// --- original form, subject to cross initialization error. ---
// int foo = 0;
// --- work-around form: no more cross initialization error. ---
int foo; foo = 0;