在C/C ++中取消初始化变量 [英] Un-initialize a variable in C/C++

查看:90
本文介绍了在C/C ++中取消初始化变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个理论问题,而不是实际问题,但是我想知道是否可以在C(或C ++)中取消初始化变量.假设我们有以下代码:

This is more a theoretical question than a practical one, but I was wondering whether is it possible to un-initialize a variable in C (or C++). So let's say we have the following code:

void some_fun()
{
    int a; // <-- Here a is an un-initialized variable, it's value is the value
           // found in the memory at the given location.
    a = 7; // Now I have initialized it 

    // do something with a ... 

    // and here do something again with a that it 
    // will have the same state (ie: indeterministic) as before initialization  
}

(不,我不想在a中放置一个随机值,因为这也将是一个初始化,也不是0,因为这是一个非常好的值,...我只是希望它再次出现在其中在初始化之前是我对此一无所知".

(No, I don't want to put a random value in a because that would be also an initialization, nor 0, because that's a very nice value, ... I just want it to be again in that "I don't know anything about it" stage it was before initializing it).

(是的,我知道:推荐答案

您可以使用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限定的,并且已在setjmplongjmp调用之间进行了更改,因此即使之前它已正确初始化,其值也是不确定的 . 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆