【发布时间】:2022-01-20 20:03:48
【问题描述】:
考虑这个例子
int main(){
std::intptr_t value = /* a special integer value */;
int* ptr = reinterpret_cast<int*>(value ); // #1
int v = *ptr; // #2
}
[expr.reinterpret.cast] p5 说
整数类型或枚举类型的值可以显式转换为指针。转换为足够大小的整数(如果实现中存在这样的整数)并返回相同指针类型的指针将具有其原始值; 指针和整数之间的映射是由实现定义的。
至少,步骤#1 是实现定义的。对于步骤#2,我认为有四种可能,分别是
- 实现不支持这种转换,实现会为它做任何事情。
- 指针值正好是
int类型对象的地址,结果格式正确。- 指针值为
int类型以外的对象地址,结果为UB。- 指针值是无效的指针值,间接是UB。
这意味着通过指针ptr 的间接行为将取决于实现。如果实现采用选项2,则不一定是UB。所以,我想知道这个案子是不是肯定是UB还是肯定是UB?如果是后者,哪些条款强烈说明了该行为?
【问题讨论】:
-
我认为关键问题是 -
*ptr是否取消引用在程序生命周期内创建的intobject?如果没有,那么我们有 UB。 -
从标准的角度来看,是的,这是未定义的行为。可以将指针映射到整数值,然后将该整数值包映射到指针 - 但映射(在任一方向)是实现定义的。除其他外,这可能意味着往返映射(例如,指向整数值的指针到指针)可能不会给出原始值。更一般地说,从整数值到指针的映射是否给出指向对象的有效指针是实现定义的。如果指针未指向有效对象,则取消引用它会产生未定义的行为。
-
@Peter 从标准的角度来看,我不认为它绝对是 UB。此外,往返映射绝对是格式良好的,因为标准保证了这一点。
-
@xmh0511 您对标准的要求和实现的功能感到困惑。在很多情况下,实现选择可靠地产生特定行为,其中行为仍未由标准定义(即没有实现提供标准是否未定义某事的标准)。在往返行为上,该标准为某些整数类型(例如
std::ptrdiff_t和std::size_t)提供了相关保证,但这些类型本身是实现定义的。其他整数类型当然没有这样的保证,比如int。 -
@Peter 我认为您对“UB”的看法与我的不同。我在问这个案子是否肯定是“UB”。实现定义的行为与“未定义的行为”无关,它们不是一回事。您应该指出
#2是 UB 还是实现定义的行为。如果肯定是UB,请在此处引用相关报价。我会很感激的。
标签: c++ language-lawyer