提问者:小点点

二reinterpret_cast严格混淆现象


这是一个典型的严格混叠违规示例:

std::uint32_t foo(float* f, std::uint32_t* i) {
    *i = 1;
    *f = 2;
    return *i;
}

int main() {
    std::uint32_t i = 3;
    foo(reinterpret_cast<float*>(&i), &i);
}

但假设我们添加第二reinterpret_cast

static_assert(alignof(float) == alignof(std::uint32_t));

std::uint32_t foo(float* f, std::uint32_t* i) {
    *i = 1;
    *reinterpret_cast<std::uint32_t*>(f) = 2;
    return *i;
}

int main() {
    std::uint32_t i = 3;
    std::uint32_t j = foo(reinterpret_cast<float*>(&i), &i);
    assert(j == 2);
}

这段代码正确吗(不调用未定义的行为)?

标准[expr.reinterpret.cast]如下:

注意:将“指针到<code>T1</code>”类型的prvalue转换为“指针到和<code>T2是对象类型,并且<code>T2的对齐要求不比<code>T 1

我们使用 std::uint32_t* 类型的原始指针值来访问 std::uint32_t 类型。

当优化打开时,GCC和Clang都会生成正确的汇编代码:

foo(float*, unsigned int*):
        mov     dword ptr [rsi], 1
        mov     dword ptr [rdi], 2
        mov     eax, dword ptr [rsi]
        ret

共1个答案

匿名用户

以下是相应的规范文本expr.static_cast/13:

类型“指向 cv1 void 的指针”的 prvalue 可以转换为类型为“指向 cv2 T”的 prvalue,其中 T 是对象类型,cv2 是与 cv1 相同的 cv 限定或大于 cv1 的 cv 限定。如果原始指针值表示内存中某个字节的地址 A,并且 A 不满足 T 的对齐要求,则生成的指针值未指定。否则,如果原始指针值指向对象 a,并且存在一个类型为 T 的对象 b(忽略 cv 限定),该对象可与 a 进行指针互转换,则结果为指向 b 的指针。否则,指针值将因转换而保持不变。

(此文本涉及,因为在这种情况下,reinterpret_cast

因此,如果符合对齐要求,则没有任何转换(uint32_t-