goto 语句

来自cppreference.com
< cpp‎ | language

无条件转移控制流。

在使用其他语句不可能转译控制到所需位置时使用。

目录

[编辑] 语法

attr(可选) goto label ;

[编辑] 解释

goto 语句转移控制到标号所指定的位置。 goto 语句必须在与它所用的 label 相同的函数中,它可出现于标号前后。

若控制转移退出任何自动变量的作用域(例如通过回跳到这种变量声明之前的点,或前跳出复合语句,其中变量处于作用域内),则为所有退出作用域的变量调用析构函数,以其构造顺序的逆序。

goto 不能转移控制流进入 try 块或 catch 子句,但能转移控制流离开 try 块或 catch 子句(遵循上述考虑作用域中的自动变量的规则)

若控制转移进入任何自动变量的作用域(例如通过前跳跨过声明语句),则程序为病态(不能编译),除非进入作用域的所有变量拥有

1) 标量类型,且声明不带初始化器
2) 拥有平凡默认构造函数和析构函数的类类型,且声明不带初始化器
3) 上述之一的 cv 限定版本
4) 上述之一的数组

(注意:相同规则应用于控制转移的所有形式)

[编辑] 关键词

goto

[编辑] 注意

在 C 编程语言中, goto 语句的限制较少,并且能进入任何异于变长数组或可变修改指针的对象的作用域。

[编辑] 示例

#include <iostream>
 
struct Object {
    // 非平凡析构函数
    ~Object() { std::cout << "d"; }
};
 
struct Trivial {
    double d1;
    double d2;
}; // 平凡构造函数与析构函数
 
int main()
{
    int a = 10;
 
    // 使用 goto 循环
label:
    Object obj;
    std::cout << a << " ";
    a = a - 2;
 
    if (a != 0) {
        goto label;  // 跳出 obj 的作用域,调用 obj 析构函数
    }
    std::cout << '\n';
 
    // goto 能用于简易地离开多层循环
    for (int x = 0; x < 3; x++) {
        for (int y = 0; y < 3; y++) {
            std::cout << "(" << x << ";" << y << ") " << '\n';
            if (x + y >= 3) {
                goto endloop;
            }
        }
    }
endloop:
    std::cout << '\n';
 
    goto label2; // 跳入 n 和 t 的作用域
    int n; // 无初始化器
    Trivial t; // 平凡构造函数/析构函数,无初始化器
//  int x = 1; // 错误:有初始化器
//  Object obj2; // 错误:无平凡析构函数
label2:
 
    {
        Object obj3;
        goto label3; // 向前跳,离开 obj3 的作用域
    }
label3: ;
 
}

输出:

10 d8 d6 d4 d2
(0;0) 
(0;1) 
(0;2) 
(1;0) 
(1;1) 
(1;2) 
 
dd

[编辑] 扩展阅读

Edsger W. Dijkstra 的著名文章《我认为 goto 有害》,呈现了大意使用此关键词会引入的各种微妙问题的考察。

[编辑] 参阅

gotoC 文档