2016-03-13 18 views
3

我正在處理一個返回字節數組的串行設備。 在這個數組中是存儲在無符號短褲和無符號字符中的值。 我有以下結構:將QByteArray中的數據放入Struct中

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; 

什麼對數組這種結構映射的最佳方式?從串行設備接收到的陣列中的順序與結構匹配。

+0

假設從線路接收到的字節的字節數也與主機字節匹配:只要使用好的「memcpy」,如果你需要結構體以保證你的'QByteArray'的生命週期。 'reinterpret_cast'否則(它會讓你省去副本,但會將結構的生命週期與QByteArray本身綁定在一起)。閱讀:讓你更容易拍攝自己的腳)。如果endianess不匹配,則需要通過'qFromLittleEndian'或'qFromBigEndian'手動轉換每個字段(具體取決於內存中的格式)。 – peppe

回答

-1

首先,我要說的是,是不是安全的包裝結構中的無符號短類型,你會序列化/反序列化和與其他設備交換:無符號短通常是16位的,但你可以沒有保證,這是平臺的依賴。

如果結構體成員沒有對齊,編譯器會在結構體中插入填充符更加糟糕。

如果從串口收到的二進制數據保存在QByteArray中,並且字節順序和「無符號短」類型都可以,那麼要在QByteArray中映射一個數據到結構中,您可以使用下面的代碼。請注意,如果您的結構已打包並且其中沒有填充間隙,則這只是正確的,請爲您的編譯器使用struct打包技術(請參閱Structure padding and packing)。

QByteArray bArr; 
bArr.resize(sizeof(fc_adv_info_t)); 
// do something to fill bArr with received data 
fc_adv_info_t* info=reinterpret_cast<fc_adv_info_t*>(bArr.data()); 
+0

是的,請使用'qint16'。它是保證結構是包裝(沒有填充內)? – Ilya

+0

當然!應該考慮結構填充。更新後。 –

+0

應該沒問題,因爲int間的字符數是偶數(我認爲)。 – Ilya

3

首先,數據的使用類似C的語法結構的類型的描述不明確。它不告訴我們shortchar類型的大小,也不告訴我們數據的字節順序! A short int不一定是16位寬,也不是char總是8位!至少,您應該使用fixed width integer types或它們的Qt等價物,並指定它們的字節順序。

另外,typedef struct是C-ism,在C++中是不必要的。丟掉typedef

假設大端包,unsigned short意味着uint16_tunsigned char意味着uint8_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聲明暗示什麼都沒有關於如何在內存中安排數據,除了選擇的安排不會導致未定義的行爲,並且必須符合標準的其他要求(只有少數幾個)。這就是所有,非常。

+0

難道你不認爲QDataStream需要額外的標題字節嗎?據我記得QDataStream爲其元數據增加4個額外的字節。只需要澄清一下QByteArray必須在串行端口的QDataStream上串行化,這對於低級別的設備控制器來說幾乎不存在。 –

+0

@EvgenyS。數據流不添加自己的標題。 「QByteArray必須在對端使用QDataStream序列化」這是錯誤的。 'QDataStream'的設計正是考慮到了這種應用。除了其他功能外,它還提供了一種便攜式方法來解析和生成C基本類型的面向字節的數據流。 –

+0

@KubaOber包裝不是完全可預測的,如果您不假定尺寸有什麼問題,那麼quint16的用法是什麼? NB'char'總是1個字節。 – Ilya