4

我已经阅读了这个关于“跳转到案例标签”错误的问题,但我仍然有一些问题。我在 Ubuntu 12.04 上使用 g++ 4.7。

此代码给出错误:

int main() {
  int foo = 1;
  switch(foo) {
  case 1:
    int i = 0;
    i++;
    break;
  case 2:
    i++;
    break;
  }
}

错误是

jump-to-case-label.cpp: In function ‘int main()’:
jump-to-case-label.cpp:8:8: error: jump to case label [-fpermissive]
jump-to-case-label.cpp:5:9: error:   crosses initialization of ‘int i’

但是,这段代码编译得很好,

int main() {
  int foo = 1;
  switch(foo) {
  case 1:
    int i;
    i = 0;
    i++;
    break;
  case 2:
    i++;
    break;
  }
}

第二个代码比第一个代码危险吗?我对为什么 g++ 允许它感到困惑。

其次,解决这个问题的方法是限定初始化变量的范围。如果初始化的变量是一个大对象,并且switch语句在while循环中,会不会每次进入和离开那个scope都会调用构造函数和析构函数,导致效率下降?或者编译器会优化这个吗?

4

4 回答 4

6

跳过对象的初始化,即使对象是 type int,也总是未定义的行为。请注意,switch-statement 的声明并没有什么特别之处:它只是一个声明,人们已经 [ab-] 使用了这种有趣的方式,例如Duff 的 Device。语句中唯一特别的地方是标签可以采用default:and的形式case <const-integer-expr>:

该语句int i;是变量的定义,但没有初始化。因此,不会绕过变量的初始化。跳过这个定义没有比一开始更大的问题了。当然,值是在跳转到case 1:而不是在跳转到时分配的,但这与人们只定义变量时在-语句case 2:之外的代码中发生的情况没有什么不同。switch

于 2012-10-20T20:07:22.903 回答
2

首先,编译器决定如何打开switch汇编代码。可能是if或可能是表goto。此外,如果您将变量初始化一起编写声明,编译器会告诉您这是error. 在另一种情况下,它会是warning(编译器会警告你,但不会拒绝你)。所以,你可以保护自己。只是它调整编译器选项,warnings它将在哪里errors。并且要正确使用 中的变量switch,您必须指定它们的范围。例如:

switch(i)
{
case 1:
{
  int j = 0;
}
break;
}

PS。对于 c++,switch 是地狱。

从 C++11 开始:

C.1.5 第 6 条:声明

6.4.2、6.6.4(switch 和 goto 语句)

更改:现在跳过具有显式或隐式初始化程序的声明是无效的(除非跨整个块未输入)

基本原理:初始化器中使用的构造函数可以分配在离开块时需要释放的资源。允许跳过初始化器需要复杂的运行时分配确定。此外,对未初始化对象的任何使用都可能是一场灾难。使用这个简单的编译时规则,C++ 可以确保如果一个已初始化的变量在范围内,那么它肯定已被初始化。

对原始特征的影响:删除语义上定义明确的特征。

从 gcc 诊断编译指示:

6.57.1​​0 诊断编译指示 诊断编译指示

GCC 允许用户有选择地启用或禁用某些类型的诊断,并更改诊断的类型。例如,一个项目的策略可能要求所有源代码都使用 -Werror 进行编译,但某些文件可能具有允许特定类型警告的异常。或者,项目可能会选择性地启用诊断并将其视为错误,具体取决于定义的预处理器宏。

PSS。编译器知道您的变量未初始化的代码块。无论它是什么static C/C++ analysis(例如,免费cppcheck)都会向您展示问题所在。

于 2012-10-20T20:34:41.973 回答
1

在第二种情况下打开警告(-Wall)给出:

foo.cpp:15:8: warning: 'i' may be used uninitialized in this function [-Wuninitialized]

跳过初始化是一个错误,但编译器不会试图在未初始化的变量上猜测你。

于 2012-10-20T20:15:26.467 回答
0

在 switch 内初始化变量会导致此错误。这是由于权限问题而发生的。尝试在开关外初始化变量并在开关内赋值。

同样的问题也适用于 C++ 线程。

于 2018-10-04T06:32:26.613 回答