C语言 将 2 个uint16_t合并为 1 个uint32_t



我有 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 11110000 0000 1111 1111...所以16711935十进制,但我得到 255 ( 0000 0000 0000 0000 0000 0000 1111 1111(。

有什么想法吗?

谢谢

在某种程度上,这是依赖于平台的。 在我最近的系统上,我们得到了预期的结果,这可以通过一个简短的程序来证明:

#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);
}

如果我不按所示使用强制转换扩大var1,这将产生0x1fe而不是0xff000000ff(因为在此系统上,<<32恰好是 32 位无符号类型的无操作(。

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

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

在这种系统中,您需要首先转换为更广泛的整数类型,如uint32_tuint64_t,然后左移。为了安全起见,我们始终可以将移位的左操作数转换为预期的type,以便我们的代码不受编译器设计器做出的实现决策(如位宽(的影响。

最新更新