繁体   English   中英

在 C 中进行移位的复合运算符或如何将 20 位 2' 补数转换为 32 位有符号整数

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

有20位2'补数(用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 位签名 integer 从右边开始有 24 个值然后:

sample /= 1L << 12;

这是如何工作的?

完整代码的链接位于:

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

通常,应在无符号 integer 类型上执行按位移位操作,因为:

  • 左移负值会导致未定义的行为。
  • 如果将任何非零位移动到或通过符号位的 position,左移一个非负的有符号值会导致未定义的行为。
  • 右移一个负值会产生一个实现定义的值。

如果您小心避免上述所有情况,则可以在带符号的 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);

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只要实现提供了int32_t ,这里的“可移植”就可以了。 如果不是,则可以改用int_least32_t

这是如何工作的?

如果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;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM