C语言 将两个无符号字符连接为一个uint16_t



我正在尝试纠正一些东西,它将采用两个无符号字符并抓住一个的 4 个较低位并将其连接到其他 8 位的前面。

x = 01234567
y = 23458901
doBitWise = 890101234567

是我正在寻找的一个例子。

unsigned char x = someNumber; 
unsigned char y = someNumber;
uint16_t result = (x & (1 << 4) - 1) | (y);

但这给了我一个警告,说结果会比uint16_t更大?我错过了什么吗?

警告是因为表达式中发生了算术转换 uint16_t result = (x & (1 << 4) - 1) | (y); 。这里(1<<4)-1将具有 int 类型,而 x 的类型为 unsigned char ,根据转换规则,结果将是 int 类型,不适合您平台上的uint16_t

参考,c11 std 6.3.1.8 关于常用算术转换:

否则,如果具有有符号整数类型的操作数的类型可以表示 具有无符号整数类型的操作数类型的所有值,然后 具有无符号整数类型的操作数将转换为 具有有符号整数类型的操作数。

要获得 4 个较低的位x,请使用 x & 0xF 。在应用移位操作之前,还要将其转换为uint16_t

uint16_t result = (uint16_t)(((x & 0xF) << 8) | y);

这会将 x 的较低 4 位放在 y 之前。您使用的表达式将用 y 降低 x 的 4 位,它不会做您想要的。

这就是我想要做的,只需取 y 的最后 4 位并将其与所有 x 放在一起。

x = 01234567
y = 23458901
doBitWise = 890101234567

在这种情况下,您应该将 y 左移 8,并屏蔽前 4 位:

uint16_t result = (((unsigned short)y << 8) & 0xF00) | x; //result will be casted to uint16_t

注意:请注意运算符优先级。 + 在<<之前,因此需要括号

注意 2:为了防止 int 为 16 位时出现未定义的行为,并确保 y <<8 的结果至少具有 16 位,添加了显式转换为无符号短字符(因为 y 最初是无符号字符)。此外,x 的插入是使用按位 OR 运算符 |。

正如其他人所说,这里的问题是在做算术之前,窄整数类型被转换为 int ,一个有符号类型。但是解决方案应该简单得多,只需强制无符号算术:

uint16_t result = (x & (1U << 4) - 1U) | (y);

在这里,文字是unsigned的,所以是<<&-然后是|运算符的结果。这是因为这些运算符如果呈现int并且unsigned总是将int部分转换为unsigned

对于从unsigneduint16_t的最终转换,这总是由模算术很好地定义,没有一个理智的编译器应该抱怨这一点。

最新更新