使用 goto 跳转到内部或同级作用域

问题描述 投票:0回答:2

是否允许跳转到内部作用域或同级作用域内的标签?如果是这样,是否允许使用在该范围内声明的变量?

考虑这段代码:

int cond(void);
void use(int);

void foo() 
{
    {
        int y = 2;
        label:
        use(y);
    }

    {
        int z = 3;
        use(z);

        /* jump to sibling scope: */
        if(cond()) goto label;
    }

    /* jump to inner scope: */
    if(cond()) goto label;
}

这些

goto
合法吗?

如果是这样,当我跳转到

y
并保持分配给它的最后一个值时,
label
是否保证存在(
2
)?

或者编译器是否允许假设

y
在超出范围后不会被使用,这意味着单个内存位置可以同时用于
y
z

如果此代码的行为未定义,我怎样才能让 GCC 发出有关它的警告?

c scope goto
2个回答
11
投票

来自C99标准(强调我的):

6.2.4 对象的存储时长

[6] 对于这样一个具有可变长度数组类型的对象,它的生命周期从对象的声明开始延伸,直到程序的执行离开声明的范围。 ...如果递归地输入范围,则“每次都会创建一个新的对象实例”。对象初始值是不确定的

6.8.6.1

goto声明


  
  [1] 

goto

语句中的标识符应命名位于

封闭函数中某处的标签。 
goto 语句不得从具有 可变修改类型
 的标识符的范围之外跳转到该标识符的范围内。
[4] ... goto

语句不允许跳过任何具有

可变修改类型

的对象声明。
结论

    y
  1. 不是

    可变修改类型

    ,因此,根据标准,跳跃是
    合法

  2. y
  3. 保证存在,但是,跳转会跳过初始化 (

    y = 2

    ),因此 
    y
     的值是 
    不确定

    您可以使用
  4. -Wjump-misses-init
  5. 让GCC发出

    警告

    ,如下所示:

    warning:

    jump skips variable initialization [-Wjump-misses-init]
    
    

  6. 在C++中,跳转是不合法的,C++不允许跳过
y
的初始化。


跳转是合法的(在 C 中,在 C++ 中则不是)。

10
投票
当我跳到

y

时,

label
保证存在

是的。

并保存分配给它的最后一个值(

2
)?


没有。

摘自

C11标准(草案)6.2.4/6

对于这样一个对象[没有存储类 说明符 static] 没有可变长度数组类型,其生命周期延长 从进入与其关联的块直到该块的执行结束 反正。 [...] 对象的初始值是不确定的。如果 为对象指定初始化,每次在执行块时到达声明 [...] 时都会执行初始化;否则,该值将变为 每次达成声明时都是不确定的。

从上面可以得出结论,第二次和第三次

use(y)
被称为“

不确定[d]

”中
y
的值,因为
y的初始化是not
reached” ”.

© www.soinside.com 2019 - 2024. All rights reserved.