C中带有移位的复合运算符或如何转换20bit 2'32位有符号整数中的补码数

Compound operator with shift in C or how to convert 20bit 2'complement number in 32bit signed int

本文关键字:20bit 符号 补码 整数 32位 复合 运算符 何转换 转换      更新时间:2024-09-21

有20位2’complement数字(用3 x 8位读取(,需要转换为32位带符号整数。

有人能解释一下这段代码吗:

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;

所以现在在右边的32位有符号整数中有24个值,然后:

sample /= 1L << 12;

这是怎么回事?

完整代码的链接位于:

https://github.com/circuitar/Nanoshield_LoadCell/blob/master/src/Nanoshield_LoadCell.cpp

这是如何工作的?

如果SPI.transfer(0)返回0-255;作品";当20比特数在读取的数据的高24比特中时。然后,将其转换为32位类型的符号位依赖于UB来形成正确的值,当被划分时,但1 << 12是受欢迎的值。

要将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;
}

通常,应该对无符号整数类型执行逐位移位操作,因为:

  • 左移负值会导致未定义的行为
  • 如果将任何非零位移位到符号位的位置或通过符号位的该位置,则对非负的有符号值进行左移位会导致未定义的行为
  • 对负值进行右移将生成实现定义的值

如果你小心避免以上所有情况,逐位移位操作可以在有符号整数类型上使用,如下所示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);

if (sample >= ...符号扩展部分可能不是无分支的,具体取决于编译器。从20位2的补码到32位有符号的另一种符号扩展转换是:

sample = (sample ^ (INT32_C(1) << 19)) - (INT32_C(1) << 20);

XOR运算将2的补码值转换为偏移二进制值。该操作可以合并到来自第一次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";便携式";这里只要CCD_ 5是由实现提供的。如果不是,则可以使用int_least32_t