这是一个理论问题而不是实际问题,但我想知道是否可以在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
}
(不,我不想在a
中放一个随机值,因为那也是一个初始化,也不是0,因为这是一个非常好的值,...我只是希望它再次在那个“我对此一无所知”的阶段,它是在初始化之前的阶段。)
(是的我知道:What happens to a declared, uninitialized variable in C? Does it have a value?)
答案 0 :(得分: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);
}
}
longjmp()
调用会返回setjmp()
的已保存上下文,而移至else
的情况意味着a
尚未初始化。
使用GCC进行优化编译时,上述函数输出:
a = 7 (initialized)
a = 1 (not initialized)
如果您希望在未启用优化的情况下执行此操作,请尝试将register
存储类添加到a
的声明中。
那么,为什么我认为setjmp()
和longjmp()
会起作用?这就是C.11§7.13¶1-2对它的评价:
标题
<setjmp.h>
定义宏setjmp
,并声明一个函数和 一种类型,用于绕过正常的函数调用和返回规则。声明的类型是
jmp_buf
这是一种适合保存恢复呼叫所需信息的数组类型 环境。 调用
setjmp
宏的环境包含信息 足以调用longjmp
函数将执行返回到正确的块和 调用该块,是否以递归方式调用。它不包括该状态 浮点状态标志,打开文件或抽象的任何其他组件 机。
这解释了应该发生的事情是longjmp
通过调用jmp_buf
回到setjmp
中保存的上下文,就好像代码一直运行到longjmp
调用是一个递归函数调用,longjmp
就像从递归调用返回setjmp
一样。对我来说,这意味着自动变量将是“未初始化的”。
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:
所有可访问的对象都具有值以及抽象机器的所有其他组件 有状态,截至调用
longjmp
函数时,除了的值 自动存储持续时间的对象,它们是包含该函数的函数的本地对象 调用没有volatile限定类型的相应setjmp
宏 并且在setjmp
调用和longjmp
调用之间进行了更改 不确定强>
由于a
是本地的,不符合规范,并且在setjmp
和longjmp
次来电之间进行了更改,因此其值不确定, 即使它在调用setjmp
之前已正确初始化!
因此,在修改了自动非易失性变量后,将longjmp
返回到本地setjmp
将始终导致在返回{{{点}之后使这些修改后的变量“未初始化” 1}}。
答案 1 :(得分: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
}
答案 2 :(得分:0)
我很好奇你为什么要那样做。但是你试过以下:
void some_fun() {
int a;
int b = a; // Hoping compiler does not discard this.
a = 7;
// do something
a = b;
}
答案 3 :(得分:0)
另一种方法是:
int a, olda;
memcpy(&olda, &a, sizeof(a));
a = 7;
//...
memcpy(&a, &olda, sizeof(a));
// a is "uninitialized"
这避免了使用赋值的陷阱表示问题,依赖于char
没有任何陷阱表示的事实。它还比使用setjmp()
和longjmp()
简单得多。