[英]Compound operator with shift in C or how to convert 20bit 2'complement number in 32bit signed int
There is 20 bit 2'complement number (which is read with 3 x 8 bit) and it needs to be converted in 32bit signed int.有20位2'补数(用3 x 8位读取),需要转换成32位有符号整数。
Could someone please explain this piece of code:有人可以解释一下这段代码:
int32_t sample = 0;
sample |= SPI.transfer(0);
sample <<= 8;
sample |= SPI.transfer(0);
sample <<= 8;
sample |= SPI.transfer(0);
sample <<= 8;
sample /= 1L << 12;
So now in 32bit signed integer from right the right side there is 24 values and then:所以现在在 32 位签名 integer 从右边开始有 24 个值然后:
sample /= 1L << 12;
How this works?这是如何工作的?
Link for the full code is at:完整代码的链接位于:
https://github.com/circuitar/Nanoshield_LoadCell/blob/master/src/Nanoshield_LoadCell.cpp https://github.com/circuitar/Nanoshield_LoadCell/blob/master/src/Nanoshield_LoadCell.cpp
In general, bit-wise shift operations should be done on unsigned integer types because:通常,应在无符号 integer 类型上执行按位移位操作,因为:
If you are careful to avoid all of the above, bit-wise shift operations can be used portably on signed integer types as in the following 1 :如果您小心避免上述所有情况,则可以在带符号的 integer 类型上可移植地使用按位移位操作,如下面的1所示:
int32_t sample = 0;
sample |= SPI.transfer(0);
sample <<= 8;
sample |= SPI.transfer(0);
sample <<= 8;
sample |= SPI.transfer(0);
sample >>= 4;
// 'sample' contains a 20-bit, 2's complement value. Sign-extend to a 32-bit signed value.
if (sample >= (INT32_C(1) << 19))
sample -= (INT32_C(1) << 20);
The if (sample >=...
sign-extension part might not be branch-free, depending on the compiler. An alternative sign-extension conversion from 20-bit 2's complement to 32-bit signed is: if (sample >=...
符号扩展部分可能不是无分支的,具体取决于编译器。从 20 位 2 的补码到 32 位符号的替代符号扩展转换是:
sample = (sample ^ (INT32_C(1) << 19)) - (INT32_C(1) << 20);
The XOR operation converts the 2's complement value to an offset binary value. XOR 运算将 2 的补码值转换为偏移二进制值。 That operation could be merged into the value of the byte from the first SPI transfer (the most significant 8 bits of the 20-bit sample value) as follows:该操作可以合并到来自第一个 SPI 传输的字节值(20 位样本值的最高有效 8 位),如下所示:
int32_t sample = 0;
sample |= SPI.transfer(0) ^ 0x80; // convert 2's complement to offset binary
sample <<= 8;
sample |= SPI.transfer(0);
sample <<= 8;
sample |= SPI.transfer(0);
sample >>= 4;
// 'sample' contains a 20-bit, offset binary value. Convert to 32-bit, signed value.
sample -= INT32_C(1) << 20;
1 "Portably" here as long as int32_t
is provided by the implementation. 1只要实现提供了int32_t
,这里的“可移植”就可以了。 If not, then int_least32_t
can be used instead.如果不是,则可以改用int_least32_t
。
How this works?这是如何工作的?
If SPI.transfer(0)
returns 0-255, it "works" when the 20-bit number is in the upper 24 bits of data read.如果SPI.transfer(0)
返回 0-255,则当 20 位数字位于读取数据的高 24 位时,它“有效”。 Then shifting that into the 32-bit type sign-bit relies on UB to form the correct value that when divided but 1 << 12
is the sought after value.然后将其转换为 32 位类型的符号位依赖于 UB 来形成正确的值,当除法时1 << 12
是寻求的值。
To convert a 20-bit 2's complement number to a int32_t
, test the sign bit.要将 20 位 2 的补码数转换为int32_t
,请测试符号位。
// Alternative without UB nor implementation defined behavior:
int32_t sample = 0;
sample |= SPI.transfer(0);
sample <<= 8;
sample |= SPI.transfer(0);
sample <<= 8;
sample |= SPI.transfer(0);
// if input is in upper 20 bits of the 24 read (OP is not explicit on that)
if (1) {
sample >>= 4;
}
assert(sample >= 0 && sample <= 0xFFFFF);
if (sample & 0x80000) { // Test for the 20-bit 2's complement sign bit
sample -= 0x100000;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.