我有 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
。
但是,您的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);
}
如果我不按所示使用强制转换扩大var1
,这将产生0x1fe
而不是0xff000000ff
(因为在此系统上,<<32
恰好是 32 位无符号类型的无操作(。
当整数类型被移位时,两个操作数首先被提升,并且生成的整数具有与提升的左操作数相同的类型。
编译器将首先尝试将uint16_t
提升为int
,如果int
无法保存该值(即该值大于INT_MAX(,则将其提升为unsigned int
。现在,如果您的系统使用16-bit int
s,结果仍将是 16 位,因此,只要您的移位值小于 16,您在左移的情况下的最高有效位就会丢失,从这一点开始,行为不受标准定义。
在这种系统中,您需要首先转换为更广泛的整数类型,如uint32_t
或uint64_t
,然后左移。为了安全起见,我们始终可以将移位的左操作数转换为预期的type
,以便我们的代码不受编译器设计器做出的实现决策(如位宽(的影响。