c++ - 改变类型而不改变位

标签 c++ c++11 types casting

我想要一个堆栈变量和reinterpret cast它转换为相同大小的无符号整数类型(以字节为单位)。例如,我可能想要 double值并将其转换为 uint64_t ,但要注意的是这些位没有被修改。我想以一种通用的方式来做。

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

我想出了一个解决方案,它在 reinterpret_cast 上使用了一个肮脏的 hack ,并且是有效的,但它需要大量的元编程才能获得相当简单的结果。

问题:有更好的方法吗?我确信存在,而且我正在使它变得比需要的更复杂。

我确实考虑过使用 T 类型的模板 union 并且大小合适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;
}

用 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

最佳答案

如果您不希望由于违反别名限制 (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;
}

高质量的编译器会优化复制。例如,这个程序:

int main() {
    return caster(3.14f);
}

effectively optimizes to return 1078523331; on Intel processors .

关于c++ - 改变类型而不改变位,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28633312/

相关文章:

c++ - 如何在指向基类对象的指针 vector 中引用派生对象?

c++ - 将键码的字符串表示形式转换为 Qt::Key(或任何 int)并返回

c++ - 在Qt/DBus适配器中实现异步功能的正确方法

scala - 如何在不发出警告的情况下匹配未知的泛型类型

swift - 为什么要限制带有 Self 或 associatedtype 的协议(protocol)?

c++ - openGL不渲染颜色

c++ - 使 C++ 暂停

c++ - std::find 包含指针的 vector

java - java的stb_loadimage()和raster.getPixels()对于同一个文件的区别

javascript - 如何在将 bool 累加器作为初始值的同时将 array.prototype.reduce() 与 TypeScript 一起使用?