c-获取对象的地址如何影响未定义的行为



在cppreference.com上,在"隐式转换"一节中,在";Lvalue转换";,注意到

[i]如果左值指定了一个自动存储持续时间的对象,该对象的地址从未被占用,并且如果该对象未初始化(未使用初始化器声明,并且在使用之前未执行任何赋值(,则行为未定义。[强调矿]

由此,我不认为";取得地址的行为";在某个时间点对一个对象的定义可能以某种方式影响未定义的行为是否稍后发生;使用";。如果我是对的,那么这至少显得不同寻常。

我说得对吗?如果是,那怎么可能呢?如果没有,我缺少什么?

cppreference.com是从C标准中的一条规则派生的。C 2018 6.3.2 2说:

如果左值指定了一个具有自动存储持续时间的对象,该对象本可以用register存储类声明(从未获取其地址(,并且该对象未初始化(未用初始化器声明,并且在使用之前未执行任何赋值(,则行为未定义。

因此,获取地址之所以重要,根本上是因为"C标准是这么说的",而不是因为获取地址在计算模型中"做了一些事情"。

将此规则添加到C标准的原因是为了支持惠普安腾处理器所需的某些行为。在该处理器中,每个特定寄存器都有一个相关的位,表示寄存器"未初始化"。因此,惠普能够让程序在某些情况下检测并捕获对象未初始化的情况。(此检测不扩展到内存;该位仅与处理器寄存器关联。(

通过说如果使用未初始化的对象,行为是未定义的,C标准允许陷阱发生,但也允许陷阱可能不会发生。因此,它允许惠普的陷阱行为,允许惠普的软件没有检测到问题,因此没有陷阱,它允许其他供应商忽略这一点,并提供寄存器中的任何值,以及编译器优化可能产生的其他行为。

至于基于自动存储持续时间而不获取地址来预测未定义的行为,我怀疑这有点草率。它提供了一个适用于相关方的标准:惠普能够设计他们的编译器,在寄存器中使用"单元化"功能,但该规则并没有将大量对象使用划分为未定义的行为。例如,有人可能想编写一种算法,整体处理许多数组的大部分,忽略了定义区域"边缘"的一些值可能未初始化。这种想法是,在某些情况下,做一系列操作,然后在最后把你不在乎的操作划掉,会更有效率。因此,对于这些情况,程序员希望代码使用"不确定值"——代码将执行,将到达操作的末尾,并且将在关心的结果中具有有效值,并且不会有任何陷阱或其他未定义的行为由他们不关心的值引起。因此,将未初始化对象的未定义行为限制为地址未被占用的自动对象,可能为所有相关方提供了一个有效的边界。

如果一个对象的地址从未被占用,那么它可能会被优化掉。在这种情况下,尝试读取未初始化的变量不需要在多次读取时产生相同的值。

通过获取一个对象的地址,可以保证为其留出存储空间,随后可以从中读取。然后读取的值至少是一致的(尽管不一定是可预测的(,假设它不是陷阱表示。

最新更新