C++ 将QByteArray中的数据放入结构中
我正在使用一个返回字节数组的串行设备。 此数组中的值存储在无符号短字符和无符号字符中。 我的结构如下:C++ 将QByteArray中的数据放入结构中,c++,arrays,qt,data-structures,C++,Arrays,Qt,Data Structures,我正在使用一个返回字节数组的串行设备。 此数组中的值存储在无符号短字符和无符号字符中。 我的结构如下: typedef struct { unsigned short RPM; //0 unsigned short Intakepress; //1 unsigned short PressureV; //2 unsigned short ThrottleV; //3 unsigned shor
typedef struct {
unsigned short RPM; //0
unsigned short Intakepress; //1
unsigned short PressureV; //2
unsigned short ThrottleV; //3
unsigned short Primaryinp; //4
unsigned short Fuelc; //5
unsigned char Leadingign; //6
unsigned char Trailingign; //7
unsigned char Fueltemp; //8
unsigned char Moilp; //9
unsigned char Boosttp; //10
unsigned char Boostwg; //11
unsigned char Watertemp; //12
unsigned char Intaketemp; //13
unsigned char Knock; //14
unsigned char BatteryV; //15
unsigned short Speed; //16
unsigned short Iscvduty; //17
unsigned char O2volt; //18
unsigned char na1; //19
unsigned short Secinjpulse; //20
unsigned char na2; //21
} fc_adv_info_t;
将数组映射到此结构的最佳方法是什么?从串行设备接收的数组中的顺序与结构匹配。首先,我要说的是,在要序列化/反序列化并与其他设备交换的结构中打包未签名的short类型是不安全的:未签名的short通常是16位,但不能保证这一点,它取决于平台 更糟糕的是,如果结构成员没有对齐,编译器就会在结构中插入填充 如果从串行端口接收的二进制数据以QByteArray格式保存,并且字节顺序和“unsigned short”类型都可以,那么要将QByteArray中的数据映射到结构上,可以使用下面的代码。请注意,只有当您的结构已打包且内部没有填充间隙时,才正确,请为编译器使用结构打包技术(请参阅)
QByteArray-bArr;
bArr.resize(sizeof(fc_adv_info));
//做点什么用接收到的数据填充bArr
fc_adv_info_t*info=reinterpret_cast(bArr.data());
首先,您使用类似C的语法描述结构中的数据类型是不明确的。它没有告诉我们short
或char
类型的大小,也没有告诉我们数据的结尾!short int
不必是16位宽,也不必是char
总是8位!至少,您应该使用或它们的Qt等价物,并指定它们的endianness
< > >代码> TyPufFrase是C-ISM,C++中不需要。放下typedef
假设一个大端数据包,unsigned short
表示uint16\u t
和unsigned char
表示uint8\u t
,下面是您可以做到的方法:
struct FcAdvInfo { // this structure shouldn't be packed or anything like that!
quint16 RPM;
quint16 IntakePress;
...
quint8 LeadingIgn;
...
FcAdvInfo parse(const QByteArray &);
};
FcAdvInfo FcAdvInfo::parse(const QByteArray & src) {
FcAdvInfo p;
QDataStream ds(src);
ds.setByteOrder(QDataStream::BigEndian);
ds
>> p.RPM
>> p.IntakePress
...
>> p.LeadingIgn
...
;
return p;
}
最后,如果您的
struct
来自某些C代码,您必须了解它是不可移植的,即使在同一个CPU上,如果您升级编译器,结构类型的打包和大小也会改变!所以不要这样做。C/C++struct
声明意味着对数据在内存中的排列方式没有任何影响,但所选择的排列方式不会导致未定义的行为,并且必须符合标准的其他要求(只有少数要求)。仅此而已。假设从线路接收的字节的尾数也与主机尾数匹配:如果需要结构在QByteArray
的使用寿命内生存,只需使用好的ol'memcpy
<代码>重新解释\u cast否则(这将节省您的副本,但会将结构的生命周期绑定到QByteArray本身。阅读:更容易击中您的脚)。如果endian不匹配,则需要通过qFromLittleEndian
或qFromBigEndian
(取决于内存中的fomat)手动转换每个字段。是的,请改用qint16
。是否保证结构是打包的(内部没有填充)?当然!应该考虑结构填充。更新的帖子。应该可以,因为int之间的字符数是偶数(我想)。是的,在这个结构中,只有最后一个字符似乎没有对齐。这是一个错误的建议。重新解释演员阵容是疯狂的。绝对没有理由将接收主机上的数据表示形式限制为与有线格式相同。在大多数情况下,访问数据的成本更高,因为每次使用数据时都必须发出代码来提取和重新对齐数据。您不认为QDataStream需要额外的标题字节吗?据我所知,QDataStream为其元数据添加了4个额外字节。必须澄清的是,QByteArray必须在串行端口的对等端用QDataStream进行序列化,这对于低级设备控制器来说是不可能的。@EvgenyS。数据流不添加自己的头。“QByteArray必须在对等端使用QDataStream进行序列化”,这是错误的QDataStream
正是针对这种应用程序而设计的。除其他功能外,它还提供了一种可移植的方法来解析和生成C基本类型的面向字节的数据流。@KubaOber打包不是完全可升级的,如果您不假设任何大小,那么这里的quint16
有什么用?NBchar
始终为1字节。
struct FcAdvInfo { // this structure shouldn't be packed or anything like that!
quint16 RPM;
quint16 IntakePress;
...
quint8 LeadingIgn;
...
FcAdvInfo parse(const QByteArray &);
};
FcAdvInfo FcAdvInfo::parse(const QByteArray & src) {
FcAdvInfo p;
QDataStream ds(src);
ds.setByteOrder(QDataStream::BigEndian);
ds
>> p.RPM
>> p.IntakePress
...
>> p.LeadingIgn
...
;
return p;
}