reinterpret_cast错误还是UB?

时间:2018-09-17 18:48:53

标签: c++ language-lawyer undefined-behavior reinterpret-cast

考虑以下代码:

#include <cstdint>
#include <algorithm>

std::uintptr_t minPointer(void *first, void *second) {
    const auto pair = std::minmax(
        reinterpret_cast<std::uintptr_t>(first),
        reinterpret_cast<std::uintptr_t>(second)
    );
    return pair.first;
}

以及GCC8在-O3上生成的程序集 https://godbolt.org/z/qWJuV_代表minPointer

minPointer(void*, void*):
  mov rax, QWORD PTR [rsp-8]
  ret

显然不符合代码创建者的意图。这段代码会导致某些UB还是GCC(8)错误?

2 个答案:

答案 0 :(得分:22)

这是UB,但这不是您可能会想的原因。

std::minmax()的相关签名是:

a = int(input("Enter first number")) 
b = int(input("Enter second number"))

在这种情况下,您的template< class T > std::pair<const T&,const T&> minmax( const T& a, const T& b ); 是对pair的一对引用。我们要引用的实际对象在哪里?是的,它们是在最后一行创建的临时文件,已经超出范围!我们有悬而未决的参考文献。

如果您写过:

uintptr_t const

然后我们没有任何悬挂的引用,您会看到gcc生成了适当的代码:

return std::minmax(
    reinterpret_cast<std::uintptr_t>(first),
    reinterpret_cast<std::uintptr_t>(second)
).first;

或者,您可以将minPointer(void*, void*): cmp rsi, rdi mov rax, rdi cmovbe rax, rsi ret 的类型显式指定为pair。或者只是完全避开该对并std::pair<std::uintptr_t, std::uintptr_t>


就语言细节而言,由于[expr.reinterpret.cast]/4,您可以将指针转换为足够大的整数类型,并且可以保证return std::min(...);足够大。因此,一旦解决了悬而未决的参考问题,就可以了。

答案 1 :(得分:13)

reinterpret_cast的定义很明确。问题在于the type of const auto pairconst std::pair<const std::uintptr_t&, const std::uintptr_t&>,因为std::minmax就是返回的内容,所以您有悬挂的引用。

您只需要摆脱悬挂的参考文献,即可正常工作:

std::uintptr_t minPointer(void *first, void *second) {
    const std::pair<std::uintptr_t, std::uintptr_t> pair = std::minmax(
        reinterpret_cast<std::uintptr_t>(first),
        reinterpret_cast<std::uintptr_t>(second)
    );
    return pair.first;
}

Godbolt link