将2 uint16_t组合成1 uint32_t

时间:2017-07-27 15:34:44

标签: c bit-shift uint32-t uint16

我有2个uint16_t,我想要组合成1个32位数字:

uint16_t var1 = 255; // 0000 0000 1111 1111
uint16_t var2 = 255; // 0000 0000 1111 1111

uint32_t var3 = (var1 << 16) +  var2;

我期望var3为0000 0000 1111 1111 0000 0000 1111 1111 ...所以16711935为十进制但我得到255(0000 0000 0000 0000 0000 0000 1111 1111)。

有什么想法吗?

由于

2 个答案:

答案 0 :(得分:2)

当移位整数类型时,首先提升两个操作数,结果整数与提升的左操作数具有相同的类型。

编译器会首先尝试将uint16_t提升为int,如果int无法保留该值(即该值大于INT_MAX),则会将其提升为unsigned int。现在,如果你的系统使用16-bit int s,结果仍然是16位,因此只要您的移位值小于16,左移的情况下最重要的位将丢失,从这一点开始标准未定义。

在这种类型的系统中,您需要首先转换为更宽的整数类型,如uint32_tuint64_t,然后左移。为了安全起见,我们总是可以将一个移位的左操作数转换为预期的type,这样我们的代码就不会受到编译器设计者做出的实现决策的影响,例如位宽。

答案 1 :(得分:1)

在某种程度上,这与平台有关。在我最近的系统上,我们得到了预期的结果,可以用一个简短的程序来证明:

#include <stdint.h>
#include <inttypes.h>
#include <stdio.h>

int main()
{
    uint16_t var1 = 255; // 0000 0000 1111 1111
    uint16_t var2 = 255; // 0000 0000 1111 1111

    uint32_t var3 = (var1 << 16) +  var2;

    printf("%#"PRIx32"\n", var3);
}

输出为0xff00ff

但是,您的var1var2会在进行任何算术之前进行正常整数提升。如果提升的类型不能保存中间结果,则部分计算可能会丢失,如您所见。

您可以通过在算术前明确扩展var1来避免此问题:

    uint32_t var3 = ((uint32_t)var1 << 16) +  var2;

我系统上等效的失败程序是:

#include <stdint.h>
#include <inttypes.h>
#include <stdio.h>

int main()
{
    uint16_t var1 = 255; // 00ff
    uint16_t var2 = 255; // 00ff

    uint64_t var3 = ((uint64_t)var1 << 32) +  var2;

    printf("%#"PRIx64"\n", var3);
}

如果我没有使用演员展开0x1fe,那么这会产生0xff000000ff而不是var1(因为在这个系统上,<<32碰巧是 - op使用32位无符号类型)。