简体   繁体   English

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

[英]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 类型上执行按位移位操作,因为:

  • Left-shifting a negative value results in undefined behavior.左移负值会导致未定义的行为。
  • Left-shifting a non-negative, signed value results in undefined behavior if any non-zero bits are shifted to or through the position of the sign bit.如果将任何非零位移动到或通过符号位的 position,左移一个非负的有符号值会导致未定义的行为。
  • Right-shifting a negative value produces an implementation-defined value.右移一个负值会产生一个实现定义的值。

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.

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