简体   繁体   English

为什么我必须在*左移之前将'uint8_t`转换为'uint64_t` *?

[英]Why must I cast a `uint8_t` to `uint64_t` *before* left-shifting it?

I just want to concatenate my uint8_t array to uint64_t. 我只想将uint8_t数组连接到uint64_t。 In fact, I solved my problem but need to understand the reason. 事实上,我解决了我的问题,但需要了解原因。 Here is my code; 这是我的代码;

    uint8_t byte_array[5];

    byte_array[0] = 0x41;
    byte_array[1] = 0x42;
    byte_array[2] = 0x43;
    byte_array[3] = 0x44;
    byte_array[4] = 0x45;

    cout << "index 0: " << byte_array[0] << " index 1: " << byte_array[1] << " index 2: " << byte_array[2] << " index 3: " << byte_array[3] << " index 4: " << byte_array[4] << endl;

    /* This does not work */
    uint64_t reverse_of_value = (byte_array[0] & 0xff) | ((byte_array[1] & 0xff) << 8) | ((byte_array[2] & 0xff) << 16) | ((byte_array[3] & 0xff) << 24) | ((byte_array[4] & 0xff) << 32);

    cout << reverse_of_value << endl;

    /* this works fine */
    reverse_of_value = (uint64_t)(byte_array[0] & 0xff) | ((uint64_t)(byte_array[1] & 0xff) << 8) | ((uint64_t)(byte_array[2] & 0xff) << 16) | ((uint64_t)(byte_array[3] & 0xff) << 24) | ((uint64_t)(byte_array[4] & 0xff) << 32);

    cout << reverse_of_value << endl;

The first output will be "44434245" and second one will be "4544434241" that is what I want. 第一个输出将是“44434245”,第二个输出将是“4544434241”,这就是我想要的。

So as we see when I use casting each byte to uint64_t code works, however, if I do not use casting it gives me irrelevant result. 因此,正如我们所看到的,当我使用每个字节转换为uint64_t代码时,如果我不使用强制转换它会给我无关的结果。 Can anybody explain the reason? 谁能解释一下原因?

Left-shifting a uint8_t that many bits isn't necessarily going to work. 向左移动uint8_t ,许多位不一定会起作用。 The left-hand operand will be promoted to int , whose width you don't know. 左侧操作数将被提升为int ,其宽度您不知道。 It could already be 64-bit, but it could be 32-bit or even 16-bit, in which case… where would the result go? 可能已经是64位,但它可能是32位甚至是16位,在这种情况下......结果会在哪里? There isn't enough room for it! 没有足够的空间! It doesn't matter that your code later puts the result into a uint64_t : the expression is evaluated in isolation. 您的代码稍后将结果放入uint64_t并不重要:表达式是uint64_t计算的。

You've correctly fixed that in your second version, by converting to uint64_t before the left-shift takes place. 您已经在第二个版本中正确修复了此问题,方法是在左移之前转换为uint64_t In this situation, the expression will assuredly have the desired behaviour. 在这种情况下,表达式肯定会具有所需的行为。

Here is an example showing left-shift turning the char to 0. At least it does so on my machine, gcc 4.8.4, Ubuntu 14.04 LTS, x86_64. 这是一个示例,显示左移将char转为0.至少它在我的机器上执行,gcc 4.8.4,Ubuntu 14.04 LTS,x86_64。

#include <iostream>

using std::cout;

int main()
{
    unsigned char ch;

    ch = 0xFF;

    cout << "Char before shift: " << static_cast<int>(ch) << '\n';
    ch <<= 10;

    cout << "Char after shift: " << static_cast<int>(ch) << '\n';
}

Note also my comment to the original question above, on some platforms, the 0x45 shifted 32 bits actually ends up in the least significant byte of the 64-bit value. 另请注意我对上述原始问题的评论,在某些平台上,0x45移位32位实际上最终位于64位值的最低有效字节中。

Shifting a type by more than the number of bits in the type is undefined behavior in C++. 在C ++中,将类型移动超过类型中的位数是未定义的行为。 See this answer for more detail: https://stackoverflow.com/a/7401981/1689844 有关更多详细信息,请参阅此答案: https//stackoverflow.com/a/7401981/1689844

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM