【问题标题】:Converting 24 bit integer (2s complement) to 32 bit integer in C++在 C++ 中将 24 位整数(2s 补码)转换为 32 位整数
【发布时间】:2016-03-08 19:12:24
【问题描述】:

dataFile.bin 是一个包含 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“数据”存储到 INT 中。如果“数据”是一个数组不是更有意义吗?由于它接收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;
}

感谢任何帮助或提示,即使您不理解任何线索或提示也会对我有很大帮助。我只需要和某人谈谈。

【问题讨论】:

    标签: c++ binary byte bit-shift


    【解决方案1】:

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

    由于char 是数字类型,将它们组合成一个int 没有问题。

    因为它接收到24个整数信息存储到一个BYTE中

    是24位,不是字节,所以只有三个整数值需要合并。

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

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

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

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

    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++ 为我们处理对结果进行符号扩展。

    【讨论】:

    • @SergeyA 糟糕,我确实复制粘贴了不必要的内容。谢谢!
    • 如果要从文件中读取 24 位 2 的补码小端 有符号 整数,在转换为 int32_t 时不需要对符号位进行位移吗?跨度>
    • @hetepeperfan 这是一个很好的观察,谢谢。由于右移&gt;&gt; 操作,Sing-extension 已经发生。请参阅我在底部添加的注释。
    【解决方案2】:

    当 unsigned char 转换为 int 时,高位用 0 填充

    当一个有符号的 char 被强制转换为一个强制转换的 int 时,符号位被扩展。 即:

    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 &amp; 0x00800000) &gt; 0 以确定是否以 0 或最高字节完成。

    【讨论】:

      【解决方案3】:
          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
      

      【讨论】:

        猜你喜欢
        • 2018-08-17
        • 1970-01-01
        • 2015-05-18
        • 2019-05-30
        • 2011-10-25
        • 1970-01-01
        • 1970-01-01
        • 2019-08-17
        • 1970-01-01
        相关资源
        最近更新 更多