在C/C++中取消初始化变量

Fer*_*eak 3 c c++ initialization

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

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  
}
Run Code Online (Sandbox Code Playgroud)

(不,我不想放一个随机值,a因为那也是一个初始化,也不是0,因为这是一个非常好的价值,...我只是希望它再次在那个"我不知道关于它的任何事情"在初始化之前进行阶段化".

(是的我知道:C中声明的,未初始化的变量会发生什么?它有值吗?)

jxh*_*jxh 7

您可以使用setjmp()longjmp()获取所需的行为,并重新安排代码.下面的代码初始化a为1,以便print语句不会调用未定义的行为.

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

longjmp()调用返回到已保存的上下文setjmp(),并且移动到该else案例意味着a尚未初始化.

当使用GCC进行优化编译时,上述函数输出:

a = 7 (initialized)
a = 1 (not initialized)
Run Code Online (Sandbox Code Playgroud)

如果您希望在未启用优化的情况下执行此操作,请尝试将register存储类添加到a声明中.

一个演示.

更长的解释

那么,为什么我认为setjmp()并且longjmp()会起作用?这就是C.​​11§7.131-2对它的评价:

标题<setjmp.h>定义了宏setjmp,并声明了一个函数和一个类型,用于绕过正常的函数调用和返回规则.

声明的类型是

jmp_buf

这是一种适合保存恢复调用环境所需信息的数组类型.调用setjmp宏的环境包括足以调用longjmp函数以将执行返回到正确的块并调用该块的信息,如果它是递归调用的.它不包括浮点状态标志,打开文件或抽象机器的任何其他组件的状态.

这解释了应该发生的事情是,通过调用longjmp保存在上下文中的回复将表现为在调用之前运行的代码是递归函数调用,这类似于从递归调用返回的行为回来了.对我而言,这意味着自动变量将是"未初始化的".jmp_bufsetjmplongjmplongjmpsetjmp

    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
    }
Run Code Online (Sandbox Code Playgroud)

但是,似乎有一个问题.从C.11§7.13.23:

所有可访问的对象都具有值,并且抽象机器的所有其他组件longjmp在调用函数时都具有状态,除了自动存储持续时间的对象的值是包含相应setjmp宏的调用的函数的本地没有volatile限定类型,并且在setjmp调用和longjmp调用之间进行了更改是不确定的.

由于a是本地的,不挥发合格,之间已经改变setjmplongjmp通话,它的价值是不确定的,即使它被调用之前正确初始化setjmp!

因此,在修改了自动非易失性变量之后使用longjmp返回本地setjmp将始终导致在返回到点之后使这些修改后的变量"未初始化" setjmp.


Pio*_*cki 6

您可以使用boost::optional<T>以下方法模拟此:

#include <boost/optional.hpp>

int main()
{   
    boost::optional<int> a;
    a = 7;

    std::cout << a.is_initialized() << std::endl; // true

    a.reset(); // "un-initialize"

    std::cout << a.is_initialized() << std::endl; // false
}
Run Code Online (Sandbox Code Playgroud)