我正在尝试纠正一些东西,它将采用两个无符号字符并抓住一个的 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
。
对于从unsigned
到uint16_t
的最终转换,这总是由模算术很好地定义,没有一个理智的编译器应该抱怨这一点。