更改类型而不更改位

bcu*_*ing 1 c++ types casting c++11

我想把一个堆栈变量和reinterpret cast它变成一个大小相同的无符号整数类型.例如,我可能想要获取double值并将其转换为a uint64_t,并且不会修改位.我想以通用的方式做到这一点.

如果我正在处理指针,我会使用reinterpret_cast<uint64_t*>(double_ptr).

我提出了一个解决方案,它使用了一个肮脏的黑客reinterpret_cast,并且是有效的,但它需要相当多的元编程来获得一个相当简单的结果.

问题是:有更好的方法吗?我确信有,并且我正在使这比需要更复杂.

我确实考虑过使用类型T和尺寸合适的模板化联合int_t,但这看起来甚至更黑,并且似乎与未定义的行为一起玩.

编辑我理解标准没有指定double应该是64位,如注释中所指出的那样.但是使用通用方法,我将能够获得与double相同大小的无符号整数类型,无论大小如此.

#include <iostream>

template <typename T, std::size_t S>
struct helper {};

template <typename T>
struct helper<T, 1> {
    using type = uint8_t;
};
template <typename T>
struct helper<T, 2> {
    using type = uint16_t;
};
template <typename T>
struct helper<T, 4> {
    using type = uint32_t;
};
template <typename T>
struct helper<T, 8> {
    using type = uint64_t;
};

template <typename T>
using int_type = typename helper<T, sizeof(T)>::type;

template <typename T>
int_type<T> caster(T value) {
    int_type<T> v;
    *reinterpret_cast<T*>(&v) = value;
    return v;
}

int main(void) {
    {
    auto val = caster(0.);
    static_assert(std::is_same<uint64_t, decltype(val)>::value, "no good");
    std::cout << sizeof(val)*8 << " " << val << std::endl;
    }

    {
    auto val = caster(0.f);
    static_assert(std::is_same<uint32_t, decltype(val)>::value, "no good");
    std::cout << sizeof(val)*8 << " " << val << std::endl;
    }

    {
    auto val = caster(-0.);
    static_assert(std::is_same<uint64_t, decltype(val)>::value, "no good");
    std::cout << sizeof(val)*8 << " " << val << std::endl;
    }

    {
    auto val = caster(-0.f);
    static_assert(std::is_same<uint32_t, decltype(val)>::value, "no good");
    std::cout << sizeof(val)*8 << " " << val << std::endl;
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

用gcc编译上面的代码给出:

> g++ --version
g++ (GCC) 4.8.2 20131016 (Cray Inc.)

> g++ -std=c++11 test.cpp && ./a.out
64 0
32 0
64 9223372036854775808
32 2147483648
Run Code Online (Sandbox Code Playgroud)

Cas*_*sey 7

如果由于违反别名限制(C++ 11 3.10/10)而不希望出现未定义的行为,则需要以字符形式访问对象表示:

template <typename T>
int_type<T> caster(const T& value) {
    int_type<T> v;
    static_assert(sizeof(value) == sizeof(v), "");
    std::copy_n(reinterpret_cast<const char*>(&value),
                sizeof(T),
                reinterpret_cast<char*>(&v));
    return v;
}
Run Code Online (Sandbox Code Playgroud)

高质量的编译器将优化副本.例如,这个程序:

int main() {
    return caster(3.14f);
}
Run Code Online (Sandbox Code Playgroud)

有效地优化了return 1078523331;英特尔处理器.