0

我有 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)。

有任何想法吗?

谢谢

4

2 回答 2

3

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

编译器将首先尝试提升uint16_tint,如果int不能保存该值(即该值大于 INT_MAX),它将被提升到unsigned int. 现在,如果您的系统使用16-bit ints ,结果仍然是 16 位,因此只要您的移位值小于 16,在左移的情况下您的最高有效位将丢失,从这一点开始,行为是未定义的标准。

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

于 2017-07-27T15:40:50.847 回答
2

在某种程度上,这取决于平台。在我最近的系统上,我们得到了预期的结果,可以用一个简短的程序来演示:

#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

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

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恰好是 32 位无符号类型的无操作)。

于 2017-07-27T16:25:47.063 回答