语句goto不能跨越变量定义吗?

33

假设这些代码在 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 编译它们没有问题,没有任何投诉。

修复错误后,我们必须在任何 goto 语句之前声明所有的指针,也就是说,即使您目前不需要这些指针(并且违反了一些原则),您也必须声明这些指针。

g++ 禁止有用的 tail-goto 语句的原始设计考虑是什么?


更新:

goto 可以跨越变量(任何类型 的变量,而不仅限于指针)声明,但除了那些被初始化的变量。如果我们删除上面的 NULL 赋值,g++ 就保持沉默了。因此,如果您想在 goto 跨区域之间声明变量,则不要对它们进行初始化(并且仍然违反一些原则)。


这应该是一个C问题还是一个C++问题?你的文件名是.c,但你正在使用g++编译,这会强制使用C++并生成特定于C++的错误。所涉及的错误是C++特定的。 - AnT stands with Russia
2个回答

44
Goto语句不能跳过变量的初始化,因为在跳转后相应的对象将不存在,因为具有非平凡初始化的对象的生命周期始于执行该初始化的时刻。C++11 §3.8/1规定了对象生命周期开始的条件。如果变量具有自动存储期,则不允许从不在其作用域内的地方跳转到其作用域内,除非该变量具有标量类型、带有平凡默认构造函数和平凡析构函数的类类型以及一个前述类型的cv限定版本的数组,并且声明时没有初始化。如果错误信息中出现[-fpermissive],可以通过指定编译器标志将其转换为警告。这表明两件事情:它曾经是被允许的(变量将存在,但在跳转后未初始化),并且gcc开发人员认为规范禁止它。编译器仅检查变量是否应该被初始化,而不检查其是否被使用,否则结果将非常不一致。但是,如果您不再需要该变量,则可以结束其生命周期,使“tail-goto”可行。
int main() {
    int a =0;
    goto exit;
    {
        int *b = NULL;
    }
exit:
    return 0;
}

是完全有效的。

另外,文件的扩展名为.c,这表明它是C语言而不是C++。如果你使用gcc而不是g++编译它,原始版本应该可以编译,因为C语言没有那个限制(它只有对于可变长度数组的限制 - 这在C++中根本不存在)。


真的,但是你的评论暗示了“变量”和“对象”之间存在某种区别,而在C++中实际上并不存在。所有变量在C++中都是对象。 - AnT stands with Russia
你完全误解了你的引用。它说:“goto语句不允许跳过任何具有可变类型对象声明。” 这里的关键是最后一部分。在C中,您可以跳过任何声明(!),即使它们已经初始化(!!),但只要它们不是可变类型。我在这里简要提到了这个区别 (https://dev59.com/PWEh5IYBdhLWcg3wVCPK#54163435)。 - AnT stands with Russia
@AnT,嗯,你说得对。那么为什么GCC认为这段代码无效呢?GCC从扩展名决定语言,而这段代码明显有.c的扩展名,因此应该被编译为C语言。在C语言中,它应该是合法的... - Jan Hudec
g++ 总是编译为 C++,而不管扩展名是什么。基于扩展名的语言检测是由 gcc 可执行文件完成的,而不是由 g++ 完成的。因此,这个问题可能是关于 C++ 的,而不是 C。尽管不清楚为什么 OP 把他们的文件命名为 .c - AnT stands with Russia

5

对于像int这样的原始类型,有一个简单的解决方法:

 // ---  original form, subject to cross initialization error.  ---
 // int foo = 0;

 // ---  work-around form: no more cross initialization error.  ---
 int foo;  foo = 0;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接