使用 goto 跳转到内部或兄弟范围
Using goto to jump to inner or sibling scope
是否允许跳转到内部范围或兄弟范围内的标签?如果是这样,是否允许使用在该范围内声明的变量?
考虑这段代码:
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
合法吗?
如果是这样,当我跳转到 label
并保留分配给它的最后一个值 (2
) 时,y
是否保证存在?
或者是否允许编译器假设 y
在超出范围后不会被使用,这意味着单个内存位置可以同时用于 y
和 z
?
如果此代码的行为未定义,我如何让 GCC 发出警告?
跳转是合法的(在 C 中,在 C++ 中它们不是)。
is y
guaranteed to exist when I jump to label
是的。
and to hold the last value assigned to it (2
)?
没有
来自C11 Standard (draft) 6.2.4/6:
For such an object [without the storage-class
specifier static] that does not have a variable length array type, its lifetime extends
from entry into the block with which it is associated until execution of that block ends in
any way. [...] The initial value of the object is indeterminate. If an
initialization is specified for the object, it is performed each time the declaration [...] is reached in the execution of the block; otherwise, the value becomes
indeterminate each time the declaration is reached.
从上面可以得出结论,第 2 次和第 3 次 use(y)
被称为 y
ins "indeterminate[d]" 的值, 因为 y
的初始化是 not "reached".
来自 C99 标准(强调我的):
6.2.4 Storage durations of objects
[6] For such an object that does have a variable length array type, its lifetime extends from the declaration of the object until execution of the program leaves the scope of the declaration. ... If the scope is entered recursively, a new instance of the object is created each time. The initial value of the object is indeterminate.
6.8.6.1 The goto
statement
[1] The identifier in a goto
statement shall name a label located somewhere in the enclosing function. A goto
statement shall not jump from outside the scope of an identifier having a variably modified type to inside the scope of that identifier.
[4] ... A goto
statement is not allowed to jump past any declarations of objects with variably modified types.
结论
y
不是 可变修改类型 ,因此,根据标准,跳转是 合法的 .
y
保证存在,但是跳转跳过了初始化(y = 2
),所以y
的值为不确定.
您可以使用 -Wjump-misses-init
让 GCC 发出 警告,如下所示:
warning:
jump skips variable initialization [-Wjump-misses-init]
在C++中,跳转是不合法的,C++不允许跳过y
的初始化。
是否允许跳转到内部范围或兄弟范围内的标签?如果是这样,是否允许使用在该范围内声明的变量?
考虑这段代码:
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
合法吗?
如果是这样,当我跳转到 label
并保留分配给它的最后一个值 (2
) 时,y
是否保证存在?
或者是否允许编译器假设 y
在超出范围后不会被使用,这意味着单个内存位置可以同时用于 y
和 z
?
如果此代码的行为未定义,我如何让 GCC 发出警告?
跳转是合法的(在 C 中,在 C++ 中它们不是)。
is
y
guaranteed to exist when I jump tolabel
是的。
and to hold the last value assigned to it (
2
)?
没有
来自C11 Standard (draft) 6.2.4/6:
For such an object [without the storage-class specifier static] that does not have a variable length array type, its lifetime extends from entry into the block with which it is associated until execution of that block ends in any way. [...] The initial value of the object is indeterminate. If an initialization is specified for the object, it is performed each time the declaration [...] is reached in the execution of the block; otherwise, the value becomes indeterminate each time the declaration is reached.
从上面可以得出结论,第 2 次和第 3 次 use(y)
被称为 y
ins "indeterminate[d]" 的值, 因为 y
的初始化是 not "reached".
来自 C99 标准(强调我的):
6.2.4 Storage durations of objects
[6] For such an object that does have a variable length array type, its lifetime extends from the declaration of the object until execution of the program leaves the scope of the declaration. ... If the scope is entered recursively, a new instance of the object is created each time. The initial value of the object is indeterminate.
6.8.6.1 The
goto
statement[1] The identifier in a
goto
statement shall name a label located somewhere in the enclosing function. Agoto
statement shall not jump from outside the scope of an identifier having a variably modified type to inside the scope of that identifier.[4] ... A
goto
statement is not allowed to jump past any declarations of objects with variably modified types.
结论
y
不是 可变修改类型 ,因此,根据标准,跳转是 合法的 .y
保证存在,但是跳转跳过了初始化(y = 2
),所以y
的值为不确定.您可以使用
-Wjump-misses-init
让 GCC 发出 警告,如下所示:warning:
jump skips variable initialization [-Wjump-misses-init]
在C++中,跳转是不合法的,C++不允许跳过y
的初始化。