推荐答案
您可以使用setjmp()
和longjmp()
来获得所需的行为,并对代码进行一些重新排列.下面的代码将a
初始化为1,以便print语句不会调用未定义的行为.
You can use setjmp()
and longjmp()
to get the behavior you want, with some rearrangement of your code. The code below initializes a
to 1 so that the print statements do not invoke undefined behavior.
jmp_buf jb;
void some_func (void)
{
int a = 1;
if (setjmp(jb) == 0) {
a = 7;
// do something
printf("a = %d (initialized)\n", a);
// use longjmp to make `a` not initialized
longjmp(jb, 1);
// NOTREACHED
} else {
printf("a = %d (not initialized)\n", a);
}
}
longjmp()
调用返回到保存的setjmp()
上下文,而转为else
情况表示a
尚未初始化.
The longjmp()
call returns back to the saved context of setjmp()
, and moving to the else
case means that a
had not been initialized.
使用GCC进行优化编译时,上述函数输出:
When compiled with GCC with optimizations, the above function outputs:
a = 7 (initialized)
a = 1 (not initialized)
如果要在未启用优化的情况下执行此操作,请尝试将register
存储类添加到a
的声明中.
If you want this behavior without optimizations enabled, try adding the register
storage class to a
's declaration.
演示.
那么,为什么我认为setjmp()
和longjmp()
可以工作?这就是C.11§ 7.13¶ 1-2所说的:
So, why did I think setjmp()
and longjmp()
would work? This is what C.11 §7.13 ¶1-2 has to say about it:
标头<setjmp.h>
定义了宏setjmp
,并声明了一个函数,并且
一种类型,用于绕过正常的函数调用和返回规则.
声明的类型为
jmp_buf
这是一种适合于保存恢复调用所需信息的数组类型
环境. setjmp
宏的调用环境由以下信息组成:
足以调用longjmp
函数将执行返回到正确的块,并且
该块的调用是否被递归调用.它不包括该块的状态
浮点状态标志,打开的文件或摘要的任何其他组件的状态标志
机器.
The header <setjmp.h>
defines the macro setjmp
, and declares one function and
one type, for bypassing the normal function call and return discipline.
The type declared is
jmp_buf
which is an array type suitable for holding the information needed to restore a calling
environment. The environment of a call to the setjmp
macro consists of information
sufficient for a call to the longjmp
function to return execution to the correct block and
invocation of that block, were it called recursively. It does not include the state of the
floating-point status flags, of open files, or of any other component of the abstract
machine.
这解释了应该发生的情况是,通过调用setjmp
返回longjmp
保存在jmp_buf
中的上下文的longjmp
就像在longjmp
调用之前一直运行的代码一样在递归函数调用中,longjmp
的作用类似于从该递归调用返回setjmp
的返回.对我来说,这意味着自动变量将被未初始化".
This explains that what is supposed to happen is that a longjmp
back to the context saved in the jmp_buf
by a call to setjmp
will act as if the code that ran up until the longjmp
call was a recursive function call, the the longjmp
acts like a return from that recursive call back the setjmp
. To me, this implies that the automatic variable would be "uninitialized".
int a;
// the following expression will be false if returning from `longjmp`
if (setjmp(jb) == 0) {
// this section of code can be treated like the `setjmp` call induced
// a recursive call on this function that led to the execution of the
// code in this body
a = 7;
//...
// assuming not other code modified `jb`, the following call will
// jump back to the `if` check above, but will behave like a recursive
// function call had returned
longjmp(jb, 1);
} else {
// `a` expected to be uninitialized here
}
但是,似乎有一个陷阱.来自C.11§ 7.13.2¶ 3:
But, there seems to be a catch. From C.11 §7.13.2 ¶3:
所有可访问对象都具有值,并且抽象机的所有其他组件
具有状态,从longjmp
函数被调用时开始,除了
自动存储持续时间的对象,该对象位于包含
调用不具有volatile限定类型的相应setjmp
宏
并且已在setjmp
调用和longjmp
调用之间进行了更改
不确定.
All accessible objects have values, and all other components of the abstract machine
have state, as of the time the longjmp
function was called, except that the values of
objects of automatic storage duration that are local to the function containing the
invocation of the corresponding setjmp
macro that do not have volatile-qualified type
and have been changed between the setjmp
invocation and longjmp
call are
indeterminate.
由于a
是本地的,不是volatile限定的,并且已在setjmp
和longjmp
调用之间进行了更改,因此即使之前它已正确初始化,其值也是不确定的 . c13> !
Since a
is local, is not volatile-qualified, and has been changed between setjmp
and longjmp
calls, its value is indeterminate, even if it was properly initialized before calling setjmp
!
因此,在修改了非易失性自动变量后,使用longjmp
返回本地setjmp
总是会导致返回setjmp
的点后使那些修改后的变量未初始化".
So, using longjmp
back to a local setjmp
after an automatic non-volatile variable has been modified will always result in making those modified variables "uninitialized" after returning to the point of the setjmp
.
这篇关于在C/C ++中取消初始化变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!