我有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)。
有什么想法吗?
由于
答案 0 :(得分:2)
当移位整数类型时,首先提升两个操作数,结果整数与提升的左操作数具有相同的类型。
编译器会首先尝试将uint16_t
提升为int
,如果int
无法保留该值(即该值大于INT_MAX),则会将其提升为unsigned int
。现在,如果你的系统使用16-bit int
s,结果仍然是16位,因此只要您的移位值小于16,左移的情况下最重要的位将丢失,从这一点开始标准未定义。
在这种类型的系统中,您需要首先转换为更宽的整数类型,如uint32_t
或uint64_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
。
但是,您的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
碰巧是 - op使用32位无符号类型)。