【问题标题】:Convert C++ type int16_t to int64_t without modifying the underlying binary在不修改底层二进制文件的情况下将 C++ 类型 int16_t 转换为 int64_t
【发布时间】:2016-11-11 06:35:17
【问题描述】:

我正在尝试为 3D 空间中的对象生成哈希码,以便可以使用二进制搜索算法在数组中快速找到它。

由于这个数组中的每个对象都有一个唯一的 XYZ 位置,我想我可以使用这三个值来生成哈希码。我使用以下代码尝试生成哈希码。

int64_t generateCode(int16_t x, int16_t y, int16_t z) {
    int64_t hashCode = z;//Set Z bits.
    hashCode <<= 16;//Shift them 16 bits.
    hashCode |= y;//Set Y bits.
    hashCode <<= 16;//Shift them 16 bits.
    hashCode |= x;//Set X bits.
}

现在这是我所知道的问题。考虑以下代码和平:

int16_t x = -1;
cout << "X: " << bitset<16>(x) << endl;//Prints the binary value of X.
int64_t y = x;//Set Y to X. This will automatically cast the types.
cout << "Y: " << bitset<64>(y) << endl;//Prints the binary value of Y.

这个程序的输出如下:

X: 1111111111111111
Y: 1111111111111111111111111111111111111111111111111111111111111111

它保留数字的数值,但更改底层二进制文件来做到这一点。我不想修改那个二进制文件,所以我可以得到如下输出:

X: 1111111111111111
Y: 0000000000000000000000000000000000000000000000001111111111111111

通过这样做,我可以从 XYZ 值创建一个唯一的哈希码,如下所示:

           Unused            X                 Y                 Z
HashCode: [0000000000000000][0000000000000000][0000000000000000][0000000000000000]

这将用于二分搜索。

【问题讨论】:

  • 如果你的数字不是实际数字,只是一系列字节,请使用无符号数。您不仅不需要签名号码的签名,它实际上会伤害您。

标签: c++ binary


【解决方案1】:

大多数编译器都会理解并优化它来做你真正想要的:

int16_t a[4] = { 0, z, y, x };
int64_t res;
memcpy(&res, a, sizeof(res));

(编译器会明白memcpy可以通过简单的64位内存操作来完成,而不是真正调用真正的memcpy

【讨论】:

  • 这是我在这里所做的更好的解决方案。实际上它真的很聪明,这就是我在我的代码中使用的。我仍然选择 Cornstalk 的解决方案作为答案,因为它更好地回答了更直接的问题。
  • 我喜欢这种方法,但值得指出的是,a 应该设置为{ z, y, x, 0 },以便保留问题中描述的确切位模式(假设是小端系统)。
  • 它仍然会产生一个唯一的哈希码,这是我最终真正需要的。
【解决方案2】:

首先将int16_t 转换为uint16_t,然后将它们合并为uint64_t,最后将其转换为int64_t

int64_t generateCode(int16_t x, int16_t y, int16_t z) {
    uint64_t hashCode = static_cast<uint16_t>(z);
    hashCode <<= 16;
    hashCode |= static_cast<uint16_t>(y);
    hashCode <<= 16;
    hashCode |= static_cast<uint16_t>(x);
    return static_cast<int64_t>(hashCode);
}

int16_t/int64_t 类型将是二进制补码表示(C 标准的 7.20.1.1 第 1 段要求这样做),因此将它们转换为相同大小的 uint*_t 将是逐位的无操作。

【讨论】:

  • 我可能会吹毛求疵,但我会在这里使用reinterpret_cast。它更好地表明了你的意图。
  • @NO_NAME:我很确定这是不合法的,而且它肯定不会编译。
  • 我在想reinterpret_cast&lt;uint16_t&amp;&gt;。编辑:我测试了它。它使用 g++ 5.3 编译
【解决方案3】:

试试int64_t y = (uint16_t) x;

这样做是为了确保添加的额外位是 0 而不是 1,因为这是无符号的。不过请务必检查符号位。

【讨论】:

    猜你喜欢
    • 2022-06-28
    • 2022-10-01
    • 1970-01-01
    • 2016-06-07
    • 1970-01-01
    • 2010-12-05
    • 1970-01-01
    • 2022-11-03
    相关资源
    最近更新 更多