引用未初始化的内存而不访问它是不是合法?
Posted
技术标签:
【中文标题】引用未初始化的内存而不访问它是不是合法?【英文标题】:Is it legal to reference uninitialized memory without accessing it?引用未初始化的内存而不访问它是否合法? 【发布时间】:2013-08-05 15:01:37 【问题描述】:以下情况,我有一个包含指向整数变量的指针的结构,如下所示:
struct Structure[] =
&Var[0], &Var[1] ,
&Var[2], &Var[3]
;
事情是:Var
在第一次填充此结构时未初始化。 (如:NULL
)
不久之后(第一次传递)变量Var
将被初始化,并且引用将相应更新。
我认为这没有任何故障的原因,但我希望您能在这方面提供专业知识。 将无效内存(带有数组下标)的引用放入这样的数组中是否合法?还是我需要针对这种情况采取不同的方法?
在第一次初始化之前,我不会访问这些变量的内容。
非常感谢。
编辑:
为了以后读者的利益:Var
是一个全局指针变量,一开始就被初始化为NULL。初始化通过使用new
将其变成一个数组。
【问题讨论】:
我有理由确定答案是否定的,并且某些优化器会破坏您的代码。 “或者我需要一种不同的方法来应对这种情况?”嗯,也许,初始化变量?Var
是引用还是指针?
什么是未初始化的,Var
或Var[0]
?如果Var
被初始化为指向“一个未初始化的内存区域”,那么你的代码就可以了。
如果Var
是一个未初始化的指针,那么这就是各个方向的UB。如果它是 T
类型的 array 且具有未初始化的 content 则这是定义的行为,只要您不 read 的内容存储在您的结构(或Var
)中的地址,直到上述位置它们自己的存储已被初始化。如果没有更多关于 Var
类型的信息,那就是我能提供的最深的评论了。
【参考方案1】:
我假设Var
是一个指针对象并且它的当前值是一个空指针。您的陈述暗示了这一点:
Var
在第一次填充此结构时未初始化。 (如:NULL
)
我还假设Var
没有在块范围内定义。如果它是在块范围内定义的,并且您没有对其进行初始化或为其分配值,那么它的值就是垃圾,不一定是空指针值,并且任何引用其值的尝试都有未定义的行为。
行为未定义。
如果Var == NULL
,则&Var[N]
具有未定义的行为。
arr[index]
根据定义等同于*(arr + index)
,因此&Var[N]
等同于&(*(Var + N))
。指针算术的行为是根据指针指向的数组对象的元素来定义的(单个对象被视为单元素数组),而空指针不指向任何东西。
题外话:
C 明确表示&*x
被评估为x
,&[x[i])
被评估为x+i
; C++ 没有这样说,所以&
的操作数必须是有效的。 C++ 有一个添加0
的特殊情况,即使对于空指针也有很好的定义(C 没有这种特殊情况)。但是&Var[0]
在 C 和 C++ 中仍然无效,但原因不同。在 C 中,它等价于 Var + 0
,但将 0
添加到空指针具有未定义的行为。在 C++ 中,它不 等同于Var + 0
;而是相当于&(*(Var + 0))
; Var + 0
是一个空指针,取消引用它有未定义的行为。)
题外话结束。
是的,只是计算一个无效地址具有未定义的行为,即使它从未被取消引用。
这是 2011 ISO C++ 标准 5.7 [expr.add] 第 5 段中的相关文本;特别注意最后:
当具有整数类型的表达式被添加或减去时 从一个指针,结果具有指针操作数的类型。如果 指针操作数指向数组对象的一个元素,而数组 足够大,结果指向一个元素偏移量 原始元素使得下标的差异 结果和原始数组元素等于积分表达式。 换句话说,如果表达式 P 指向一个 数组对象,表达式 (P)+N(等价于 N+(P))和 (P)-N (其中 N 的值为 n)分别指向 i + n-th 和 i − 数组对象的第 n 个元素,前提是它们存在。此外,如果 表达式 P 指向数组对象的最后一个元素, 表达式 (P)+1 指向数组对象的最后一个元素, 如果表达式 Q 指向数组的最后一个元素 对象,表达式 (Q)-1 指向数组的最后一个元素 目的。如果指针操作数和结果都指向元素 相同的数组对象,或数组的最后一个元素 对象,评估不应产生溢出;否则, 行为未定义。
【讨论】:
您能否提供禁止对空指针进行算术运算的参考?还是我误解了你的意思? @MarkB 这与NULL
的法律定义有关。如果NULL
定义为((void*)0)
(在C 中合法,在C++ 中非法),那么对其进行任何算术都是非法的。 (显然,如果 NULL
被定义为 0
,那么 NULL + 0
是合法的。)
另外,NULL + 1
在 C++ 中应该没问题。但是,尝试使用结果来初始化指针是行不通的,因为0 + 1
可能是一个整数常量表达式,但它肯定不会计算为 0。
"(C 明确表示 &*x 被计算为 x,而 &[x[i]) 被计算为 x+i;C++ 没有这样说,所以 & 的操作数有是有效的。)”似乎这意味着当Var
是空指针时,即使&Var[0]
在C++中也无效。
@ATaylor:为了未来读者的利益,请使用该信息更新您的问题。【参考方案2】:
由于在第一次传递之后才使用这些值,因此请做正确的事情并将结构的指针初始化为 null。然后在你知道它们的时候输入正确的值。如果您采用这种方法,您的“是否合法”问题就会消失!
【讨论】:
+1。其实struct Structure[2];
就够了。如果从未使用过初始化结果,则无需进行此初始化。【参考方案3】:
回答具体问题(忘记示例代码):是的,您可以引用未初始化的内存,您根本无法取消引用它并期望定义的行为。
【讨论】:
以上是关于引用未初始化的内存而不访问它是不是合法?的主要内容,如果未能解决你的问题,请参考以下文章