1

我有以下结构:

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] 中获取它的值。

知道为什么会这样吗?

4

2 回答 2

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

}

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

于 2013-01-15T00:54:17.013 回答
2

默认情况下不打包结构,因此编译器可以自由地在成员之间插入填充。最常见的原因是为了确保某些机器相关的对齐。关于数据结构对齐维基百科条目是一个很好的起点。你基本上有两个选择:

  1. 插入编译器特定的编译指示以强制对齐(例如,#pragma packed__attribute__((packed))__.
  2. 编写显式序列化和反序列化函数以将结构转换为字节数组和从字节数组转换为字节数组

我通常更喜欢后者,因为它不会让我的代码变得丑陋,到处都有很少的编译器特定的装饰。

接下来您可能会发现多字节整数的字节顺序也是特定于平台的。 查找字节序以获取更多详细信息

于 2013-01-15T00:56:27.793 回答