在项目过程中,遇到一个小端模式的数据解析问题,之前没有转化的经验,折腾了好久才转化成功,记录下来
首先,解释下什么是小端模式和大端模式
- 大端模式(Big Endian):数据的高字节,保存在内存的低地址中;数据的低字节,保存在内存的高地址中。
- 小端模式(Little Endian):数据的高字节,保存在内存的高地址中;数据的低字节,保存在内存的低地址中。
举一个例子,比如数字0x12 34 56 78在内存中的表示形式为:
1)大端模式:
低地址 -----------------> 高地址
0x12 | 0x34 | 0x56 | 0x78
2)小端模式:
低地址 ------------------> 高地址
0x78 | 0x56 | 0x34 | 0x12
可见,大端模式和字符串的存储模式类似。
然后就是具体的转化过程了,项目背景是解析某惯导产品的数据,第46/47/48个字节表示东向速度,但是是用小端模式保存的(MSB LSB:起始地址为最高位, 最后地址为最低位。LSB MSB:起始地址为最低位,最后地址为最高位。)
接收完原始数据后,为了显示和保存方便,将数据存储为16进制字符串的形式,如原始数据是三个字节0x01 0x02 0x03,保存为QString类型“010203”,然后采用如下的方法进行数据的解析
//小端数据转为大端数据,并解析
//输入的数据是3个16进制字符串,如“FF002A”,进行移位操作时需要先分开
int MainWindow::changeEndian(QString qstr)
{
//用int移位的方法
bool ok;
QString str1 = qstr.mid(0,2);
QString str2 = qstr.mid(2,2);
QString str3 = qstr.mid(4,2);
uint data1 = str1.toInt(&ok,16);
uint data2 = str2.toInt(&ok,16);
uint data3 = str3.toInt(&ok,16);
int num = (data3 << 16) + (data2 << 8) + data1;
//用char* 移位的方法,注意此时输入的不能是16进制字符串,而应该转化为对应的字符,才可以移位操作
// string str = qstr.toStdString();
// //qDebug() << "QString " << qstr << endl;
// cout << "str " << str << endl;
// const char* data = str.data();
// cout << "char " << data << endl;
// uint8_t data2 = uint8_t(*(data+4));
// uint8_t data1 = uint8_t(*(data+1));
// uint8_t data0 = uint8_t(*(data));
// cout << "data+2 " << data2 << " data+1 " << data1 << " data0 " << data0 << endl;
// uint8_t num = (uint8_t(*(data + 2) << 16) + uint8_t(*(data+1) << 8) + uint8_t(*data));
//FFFFFF对应的最大值是16777216,一半值来区分正负,注意负数采用补码方法
if(num >= 8388608)
num = num - 16777216;
//cout << "num " << num << endl;
return num;
}