无条件转移控制流。

当使用其他语句不可能将控制转移到所需位置时使用。

语法

属性(可选) goto 标号 ;

解释

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

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

goto 不能将控制转移到 try 块或 catch 子句之内,但能将控制转移离开 try 块或 catch 子句(遵循上述有关作用域中的自动变量的规则)

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

1) 标量类型,且声明不带初始化器

2) 拥有平凡默认构造函数和析构函数的类类型,且声明不带初始化器

3) 上述之一的 cv 限定版本

4) 上述之一的数组

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

关键词

goto

注意

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

示例

运行此代码

  1. #include <iostream>
  2.  
  3. struct Object {
  4. // 非平凡析构函数
  5. ~Object() { std::cout << "d"; }
  6. };
  7.  
  8. struct Trivial {
  9. double d1;
  10. double d2;
  11. }; // 平凡构造函数与析构函数
  12.  
  13. int main()
  14. {
  15. int a = 10;
  16.  
  17. // 使用 goto 循环
  18. label:
  19. Object obj;
  20. std::cout << a << " ";
  21. a = a - 2;
  22.  
  23. if (a != 0) {
  24. goto label; // 跳出 obj 的作用域,调用 obj 析构函数
  25. }
  26. std::cout << '\n';
  27.  
  28. // goto 可用于简单地离开多层循环
  29. for (int x = 0; x < 3; x++) {
  30. for (int y = 0; y < 3; y++) {
  31. std::cout << "(" << x << ";" << y << ") " << '\n';
  32. if (x + y >= 3) {
  33. goto endloop;
  34. }
  35. }
  36. }
  37. endloop:
  38. std::cout << '\n';
  39.  
  40. goto label2; // 跳入 n 和 t 的作用域
  41. int n; // 无初始化器
  42. Trivial t; // 平凡构造函数/析构函数,无初始化器
  43. // int x = 1; // 错误:有初始化器
  44. // Object obj2; // 错误:无平凡析构函数
  45. label2:
  46.  
  47. {
  48. Object obj3;
  49. goto label3; // 向前跳,离开 obj3 的作用域
  50. }
  51. label3: ;
  52.  
  53. }

输出:

  1. 10 d8 d6 d4 d2
  2. (0;0)
  3. (0;1)
  4. (0;2)
  5. (1;0)
  6. (1;1)
  7. (1;2)
  8.  
  9. dd

扩展阅读

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