在C++中将24位整数(二进制补码)转换为32位整数

4
是一个二进制文件,每个记录有6字节。每个记录的前3个字节包含纬度信息,后3个字节包含经度信息。每个24位的值代表弧度乘以0X1FFFFF。这是我正在处理的任务。因为我已经好几年没有使用C++了,所以花费的时间比我预想的要长得多。在搜索过程中,我看到了这个算法,它对我来说很有意义。
int interpret24bitAsInt32(byte[] byteArray) {     
 int newInt = (  
     ((0xFF & byteArray[0]) << 16) |  
     ((0xFF & byteArray[1]) << 8) |   
     (0xFF & byteArray[2])  
   );  
 if ((newInt & 0x00800000) > 0) {  
   newInt |= 0xFF000000;  
 } else {  
   newInt &= 0x00FFFFFF;  
 }  
return newInt;  
}  

问题是语法问题,我限制了按照另一个人编程的方式工作。我不理解如何将CHAR“data”存储到INT中。如果“data”是一个数组,是否更有意义?因为它接收24个整数的信息存储在BYTE中。
double BinaryFile::from24bitToDouble(char *data) {
    int32_t iValue;

    // ****************************
    // Start code implementation
    // Task: Fill iValue with the 24bit integer located at data.
    // The first byte is the LSB.
    // ****************************
//iValue += 
    // ****************************
    // End code implementation
    // ****************************
    return static_cast<double>(iValue) / FACTOR;
}

bool BinaryFile::readNext(DataRecord &record)
{
    const size_t RECORD_SIZE = 6;
    char buffer[RECORD_SIZE];
    m_ifs.read(buffer,RECORD_SIZE);
    if (m_ifs) {
        record.latitude = toDegrees(from24bitToDouble(&buffer[0]));
        record.longitude = toDegrees(from24bitToDouble(&buffer[3]));
        return true;
    }
    return false;
}

double BinaryFile::toDegrees(double radians) const
{
    static const double PI = 3.1415926535897932384626433832795;
    return radians * 180.0 / PI;
}

我非常感激任何帮助或提示,即使您不理解也没关系,一点线索或提示对我都有很大的帮助。我只需要和某个人交流。

3个回答

14

我不明白如何将CHAR“data”存储到INT中。

由于char是数字类型,因此将它们合并成单个int没有问题。

它接收的是24个存储在BYTE中的信息的整数。

这是24位,而不是字节,因此只需要组合三个整数值。

不使用条件语句产生相同结果的更简单方法如下:

int interpret24bitAsInt32(byte[] byteArray) {     
    return (  
        (byteArray[0] << 24)
    |   (byteArray[1] << 16)
    |   (byteArray[2] << 8)
    ) >> 8;  
}

这个想法是将输入的三个字节存储到四字节int三个字节中,然后将其向下移动一个字节。 这样程序会自动对您的数字进行符号扩展,避免条件执行。

关于可移植性的说明:此代码不可移植,因为它假定32位整数大小。要使其可移植,请使用<cstdint>类型:

int32_t interpret24bitAsInt32(const std::array<uint8_t,3> byteArray) {
    return (  
        (const_cast<int32_t>(byteArray[0]) << 24)
    |   (const_cast<int32_t>(byteArray[1]) << 16)
    |   (const_cast<int32_t>(byteArray[2]) << 8)
    ) >> 8; 
}

这还假设24位数字中最重要的字节存储在byteArray的最初元素中,然后是中间元素,最后是最不重要的字节。

关于符号扩展的注释:此代码通过先构建上三个字节中的值,然后右移来自动处理符号扩展,而不是直接在下三个字节中构建值。此附加的移位操作确保C++会为我们处理符号扩展的结果。


1
@SergeyA 哎呀,我确实复制粘贴了比必要的更多。谢谢! - Sergey Kalinichenko
如果从文件中读取一个24位的2的补码小端有符号整数,当转换为int32_t时,是否需要将符号位进行位移? - hetepeperfan
@hetepeperfan 这是一个很好的观察,谢谢。由于右移操作 >> 的出现,sing-extension 已经在发生了。请看我在底部添加的注释。 - Sergey Kalinichenko

0

当将无符号字符转换为整数时,高位比特将填充为0。

当有符号字符转换为整数时,符号位被扩展。 例如:

int x;
char y;
unsigned char z;
y=0xFF
z=0xFF
x=y;
/*x will be 0xFFFFFFFF*/
x=z;
/*x will be 0x000000FF*/

所以,你的算法使用0xFF作为掩码来移除C'符号扩展,即

0xFF == 0x000000FF
0xABCDEF10 & 0x000000FF == 0x00000010

然后使用位移和逻辑与操作将位放置在正确的位置。

最后检查最高有效位(newInt & 0x00800000) > 0,以决定是否用0或1来补全最高字节。


-2
    int32_t upperByte   = ((int32_t) dataRx[0] << 24);
    int32_t middleByte  = ((int32_t) dataRx[1] << 16);
    int32_t lowerByte   = ((int32_t) dataRx[2] << 8);

    int32_t ADCdata32 = (((int32_t) (upperByte | middleByte | lowerByte)) >> 8);     // Right-shift of signed data maintains signed bit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接