结构填充不正确

时间:2013-01-15 00:50:59

标签: qt struct bytearray

我有以下结构:

typedef union
{
    struct
    {
        unsigned char       ID;
        unsigned short      Vdd;

        unsigned char       B1State;
        unsigned short      B1FloatV;
        unsigned short      B1ChargeV;
        unsigned short      B1Current;
        unsigned short      B1TempC;
        unsigned short      B1StateTimer;
        unsigned short      B1DutyMod;

        unsigned char       B2State;
        unsigned short      B2FloatV;
        unsigned short      B2ChargeV;
        unsigned short      B2Current;
        unsigned short      B2TempC;
        unsigned short      B2StateTimer;
        unsigned short      B2DutyMod;

    } bat_values;
    unsigned char buf[64];
} BATTERY_CHARGE_STATUS;

我从数组中填充如下:

for(unsigned char ii = 0; ii < 64; ii++) usb_debug_data.buf[ii]=inBuffer[ii];

我可以看到该数组具有以下(任意)值:

inBuffer[0] = 80;
inBuffer[1] = 128;
inBuffer[2] = 12;
inBuffer[3] = 0;
inBuffer[4] = 23;
...

现在我希望通过更改QEditLine的文本来显示这些值:

str=QString::number((int)usb_debug_data.bat_values.ID);
ui->batID->setText(str);
str=QString::number((int)usb_debug_data.bat_values.Vdd)
ui->Vdd->setText(str);
str=QString::number((int)usb_debug_data.bat_values.B1State)
ui->B1State->setText(str);
...

但是,QEditLine文本值未按预期显示。我看到以下内容:

usb_debug_data.bat_values.ID = 80 (correct)
usb_debug_data.bat_values.Vdd = 12 (incorrect)
usb_debug_data.bat_values.B1State = 23 (incorrect)

似乎是'usb_debug_data.bat_values.Vdd',这是一个短片,没有从inBuffer [1]和inBuffer [2]中获取它的值。同样,'usb_debug_data.bat_values.B1State'应该从inBuffer [3]中获取它的值,但出于某种原因从inBuffer [4]中获取它的值。

知道为什么会这样吗?

2 个答案:

答案 0 :(得分:3)

C和C ++可以自由地在结构的元素之间插入填充,并且在最后一个元素之外,无论出于何种目的(通常是效率,但有时因为底层架构根本不允许未对齐访问)。

所以你可能会发现两个字节长度的项目与两个字节的边界对齐,所以你最终会得到类似的东西:

unsigned char       ID;          // 1 byte
//                                  1 byte filler, aligns following short
unsigned short      Vdd;         // 2 bytes
unsigned char       B1State;     // 1 byte
//                                  3 bytes filler, aligns following int
unsigned int        myVar;       // 4 bytes

许多编译器将允许您具体说明如何打包结构,例如:

#pragma pack(1)

gcc

__attribute__((packed))

属性。

如果您不想(或不能)打包您的结构,您可以恢复逐个字段的复制(可能是函数中最好的):

void copyData (BATTERY_CHARGE_STATUS *bsc, unsigned char *debugData) {

    memcpy (&(bsc->ID), debugData, sizeof (bsc->ID));
    debugData += sizeof (bsc->ID);

    memcpy (&(bsc->Vdd), debugData, sizeof (bsc->Vdd));
    debugData += sizeof (bsc->Vdd);

    : : :

    memcpy (&(bsc->B2DutyMod), debugData, sizeof (bsc->B2DutyMod));
    debugData += sizeof (bsc->B2DutyMod); // Not really needed

}

你必须保持结构和功能的同步,这是一种痛苦,但希望它不会发生那么大的变化。

答案 1 :(得分:2)

默认情况下,结构不是压缩,因此编译器可以在成员之间插入填充。最常见的原因是确保一些机器相关的对齐。 wikipedia entry on data structure alignment是一个非常好的起点。你基本上有两个选择:

  1. 插入编译器特定的编译指示以强制对齐(例如,#pragma packed__attribute__((packed))__
  2. 编写显式序列化和反序列化函数,以将结构转换为字节数组和从字节数组转换
  3. 我通常更喜欢后者,因为它并没有让我的代码变得丑陋,而且在任何地方都没有特定的编译器特定装饰。

    您可能会发现的下一件事是多字节整数的字节顺序也是特定于平台的。 Look up endianness for more details