0

我从硬件寄存器中得到一些值,这些值存储在 16 位无符号整数中,但这些值实际上是有符号的。知道最后一位是符号位,一位同事做了以下代码片段将它们转换为 2 的补码值:

/* Take 15 bits of the data (last bit is the sign) */
#define DATAMASK 0x7FFF

/* Sign is bit 15 (starting from zero) with the 15 bit data */
#define SIGNMASK 0x8000
#define SIGNBIT  15


int16_t calc2sComplement(uint16_t data)
{
     int16_t temp, sign;
     int16_t signData;

     sign  = (int16_t)((data & SIGNMASK) >> SIGNBIT);

     if (sign) 
     {
          temp = (~data) & DATAMASK;
          signData = (short)(temp * -1);
     }
     else 
     {
          temp = (data & DATAMASK);
          signData = temp;
     }

     return(signData);
}

据我所知,无符号整数类型和有符号整数类型的区别仅在于它们的类型和最后一位的含义;所以像下面这样的铸造也应该起作用:

int16_t calc2sComplement(uint16_t data)
{
     return(static_cast<int16_t>(data));
}

当需要将值推送到硬件时,与计算不同,反向操作很简单。前一种解决方案的优点是它没有工具链;因为它迟早会改变(gcc 4.4.7,所以 C++03),我宁愿不必这样做,但几年后编译时不会有任何回归。后者的优点是可读性更强,更接近标准,避免不必要的操作。

如果在工具链更改后再次编译(即使标准类型在工具链中的某处重新定义,而我并没有真正掌握它) ,在我的情况下,最好的方法是确保保持相同的行为?如果您保留第一个解决方案,如何改进它和/或编码反向转换(请记住,数据可以是数据缓冲区上的指针)?

4

1 回答 1

1

最后,让我们来回答我自己。因此,将值转换为二进制补码或从二进制补码转换并防止任何意外行为的最佳方法是执行二进制补码转换,如下所示:

int16_t calc2sComplement(uint16_t data)
{
     return(static_cast<int16_t>(data));
}

并做相反的操作:

uint16_t inv2sComplement(int16_t data)
{
     return(static_cast<uint16_t>(data));
}

这种方法被证明是完全安全的(只要原语类型没有在工具链中的某处重新定义——这被认为是不好的做法,但实际上是我的情况,因此我的问题排在第一位)依赖于构建的原语的定义-输入类型。

于 2017-07-24T11:42:13.517 回答