从块外部转到经过初始化变量声明后是否保证会产生编译错误? 我有一些简单的C++代码: #include <iostream> int main(){ { int a = 10; tag: std::cout << a << std::endl; } goto tag; return 0; } #包括 int main(){ { INTA=10; 标签: std::cout
正如您提到的问题的第一条评论所说,行为是未定义的。这基本上意味着每个编译器都可以随意解释您的代码。显然,您的编译器看到问题并抛出错误,而另一个编译器可能允许编译代码,特别是如果它是scop的内部表示形式e允许循环发生。正如您提到的问题的第一条注释所说,行为是未定义的。这基本上意味着每个编译器都可以随意解释您的代码。显然,您的编译器看到问题并抛出错误,而不同的编译器可能允许编译代码,特别是在代码是内部的情况下范围表示允许循环发生。 < P>我注意到问题中的代码是C++代码而不是C代码。然而,问题是C和C++双重标记,这是非常讨厌的,因为C和C++的规则是不同的。 代码不能在C++中编译,但C中编译的等效代码 <问题>中的C++代码不应该编译。C编写的类似代码应该编译,但结果是无限循环。< /P> C++11 在ISO/IEC 14882:2011(C++11标准;我没有2014标准的正式副本报告)中,它说: 6.6.4 goto声明[stmt.goto] ^1从块外部转到经过初始化变量声明后是否保证会产生编译错误? 我有一些简单的C++代码: #include <iostream> int main(){ { int a = 10; tag: std::cout << a << std::endl; } goto tag; return 0; } #包括 int main(){ { INTA=10; 标签: std::cout,c++,C++,正如您提到的问题的第一条评论所说,行为是未定义的。这基本上意味着每个编译器都可以随意解释您的代码。显然,您的编译器看到问题并抛出错误,而另一个编译器可能允许编译代码,特别是如果它是scop的内部表示形式e允许循环发生。正如您提到的问题的第一条注释所说,行为是未定义的。这基本上意味着每个编译器都可以随意解释您的代码。显然,您的编译器看到问题并抛出错误,而不同的编译器可能允许编译代码,特别是在代码是内部的情况下范围表示允许循环发生。 < P>我注意到问题中的代码是C++代码而不是C代码。然而,问题是
goto
语句无条件地将控制权转移到由标识符标记的语句。标识符应为位于当前函数中的标签(6.1)
6.7声明声明[stmt.dcl]
^1声明语句在块中引入一个或多个新标识符;其形式为声明语句:
块声明
如果声明引入的标识符以前在外部块中声明过,则外部声明将对块的其余部分隐藏,之后将恢复其效力
每次执行声明语句时,初始化2个具有自动存储持续时间(3.7.3)的变量。在块中声明的具有自动存储持续时间的变量在退出块时销毁(6.6)
^3可以传输到块中,但不能以通过初始化绕过声明的方式。从具有自动存储持续时间的变量不在范围内的点跳到其在范围内的点的程序是格式错误的,除非该变量具有标量类型、具有普通默认构造函数的类类型和平凡析构函数,这些类型之一的cv限定版本,或上述类型之一的数组,在没有初始值设定项的情况下声明(8.5)
87)在这方面,从switch语句的条件到case标签的转换被视为跳转
虽然普通的int
是标量类型,但跳转绕过初始化,因此不允许
C11
ISO/IEC 9899:2011(C11标准)中规定:
6.8.6.1goto
语句
约束^1
goto
语句中的标识符应命名位于封闭函数某处的标签。goto
语句不得从具有可变修改类型的标识符的范围外跳转到该标识符的范围内
语义^2 goto语句导致无条件跳转到封闭函数中以命名标签为前缀的语句 注意,约束冲突需要诊断。语义部分中的规则冲突不需要诊断 在附录I(常见警告)中,它是一个信息性附录,而不是一个规范性附录,它说: -具有自动存储持续时间的对象初始化的块跳转到(6.2.4) 及 6.2.4物品的储存期限 ^5标识符声明为无链接且没有存储类说明符
static
的对象具有自动存储持续时间,某些复合文字也具有自动存储持续时间。尝试从与对象关联的线程以外的线程间接访问具有自动存储持续时间的对象的结果是心理状态定义
^6对于不具有可变长度数组类型的对象,其生存期从进入与其关联的块开始,一直到该块的执行以任何方式结束。(输入封闭块或调用函数将暂停但不结束当前块的执行。)如果以递归方式输入块,则每次都会创建对象的新实例。对象的初始值是不确定的。如果为对象指定了初始化,则每次在执行块时达到声明或复合文字时都会执行该初始化;否则,每次已达成声明
^7对于具有可变长度数组类型的此类对象,其生命周期从对象声明开始,直到程序的执行离开声明的范围。35)如果以递归方式输入范围,则每次都会创建对象的新实例。对象的初始值是不确定的
35)离开包含声明的最里面的块,或跳到该块中的某个点或声明之前的嵌入块,将离开声明的范围
<>注意,在代码中没有可变的修改类型(没有VLA或可变长度数组)。标准C++不支持VLAs的概念(尽管GNU C++编译器确实允许它们作为扩展)。
代码(goto1.c
):
那是相当不错的
#include <stdio.h>
int main(void)
{
{
int a = 10;
tag:
printf("%d\n", a);
}
goto tag;
return 0;
}
$ gcc -std=c11 -O3 -g -Wall -Wextra -Werror goto1.c -o goto1
$