将 2 uint16_t 合并为 1 uint32_t
Combining 2 uint16_t into into 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 1111 0000 0000 1111 1111... 所以十进制为 16711935 但我得到 255(0000 0000 0000 0000 0000 0000 1111 1111)。
有什么想法吗?
谢谢
当一个整数类型被移位时,两个操作数首先被提升,并且生成的整数与提升的左操作数具有相同的类型。
编译器将首先尝试将 uint16_t
提升为 int
,如果 int
不能保存该值(即该值大于 INT_MAX)它将晋升为 unsigned int
。现在,如果您的系统使用 16-bit int
s,结果仍将是 16 位,因此只要您的移位值小于 16,则在左移的情况下您的最高有效位将丢失,从这一点开始行为未按标准定义。
在那种系统中,您需要先转换为更宽的整数类型,例如 uint32_t
或 uint64_t
,然后左移。为了安全起见,我们始终可以将移位的左操作数转换为预期的 type
,这样我们的代码就不会受到编译器设计者做出的实现决策(例如位宽)的影响。
在某种程度上,这取决于平台。在离我最近的系统上,我们得到了预期的结果,可以用一个简短的程序来演示:
#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 位无符号类型的无操作)。
我有 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)。
有什么想法吗?
谢谢
当一个整数类型被移位时,两个操作数首先被提升,并且生成的整数与提升的左操作数具有相同的类型。
编译器将首先尝试将 uint16_t
提升为 int
,如果 int
不能保存该值(即该值大于 INT_MAX)它将晋升为 unsigned int
。现在,如果您的系统使用 16-bit int
s,结果仍将是 16 位,因此只要您的移位值小于 16,则在左移的情况下您的最高有效位将丢失,从这一点开始行为未按标准定义。
在那种系统中,您需要先转换为更宽的整数类型,例如 uint32_t
或 uint64_t
,然后左移。为了安全起见,我们始终可以将移位的左操作数转换为预期的 type
,这样我们的代码就不会受到编译器设计者做出的实现决策(例如位宽)的影响。
在某种程度上,这取决于平台。在离我最近的系统上,我们得到了预期的结果,可以用一个简短的程序来演示:
#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 位无符号类型的无操作)。