联盟成员数据对齐

时间:2014-02-13 22:40:56

标签: c unions

我在联合中遇到了一些数据对齐问题,我似乎无法弄清楚。使用类似于下面的联合,联盟的基地址似乎有一些数据偏移。

typedef union MyUnion
{
    struct MyStruct
    {
        uint16_t val_1;
        uint8_t  val_2;
        uint8_t  val_3;
    }data;
    uint8_t data_array[4];
}MyUnion;

在某些时候,我已经用数据填充了结构,

my_union.data.val_1 = 65535;
my_union.data.val_2 = 0;
my_union.data.val_3 = 0;
然后我尝试使用数组访问数据。我期望在数组的基地址看到的是val_1的第一个字节,255。但是,当访问数组中的数据时,它似乎从结构的基数偏移了1个字节。

printf("Bytes of struct: %#08x\n", my_union.data.val_1);
printf("Bytes of array:  %#08x\n", my_array.data_array[0]);

无论我在上面的结果中输入什么值,输出都与此类似。

Bytes of struct:  0x00ffff
Bytes of array:   0x0000ff

我首先想到成员可能会以某种方式偏移并引用不同的内存地址,但是当我打印他们的地址时,它们是相同的。

另外,如果我打印以下值,它们是相同的。

printf("Bytes of struct: %#08x\n", my_union.data);
printf("Bytes of array:  %#08x\n", *(my_array.data_array - 1) );

输出:

    Bytes of struct:  0x00ffff
    Bytes of array:   0x00ffff

我确定我错过了一些简单的东西,但此刻我无法理解。感谢您提前提供任何帮助。

3 个答案:

答案 0 :(得分:2)

在小端机器上运行(英特尔酷睿i7,Mac OS X 10.9.1 Mavericks,GCC 4.8.2),以下程序:

#include <inttypes.h>
#include <stdio.h>

typedef union MyUnion
{
    struct MyStruct
    {
        uint16_t val_1;
        uint8_t  val_2;
        uint8_t  val_3;
    } data;
    uint8_t data_array[4];  // NB: was unint8_t!!!
} MyUnion;

int main(void)
{
    MyUnion my_union;

    my_union.data.val_1 = 0xFEDC;
    my_union.data.val_2 = 0xBA;
    my_union.data.val_3 = 0x98;

    printf("val_1 = 0x%.4" PRIX16 "; val_2 = 0x%.2" PRIX8 "; val_3 = 0x%.2" PRIX8 "\n",
           my_union.data.val_1, my_union.data.val_2, my_union.data.val_3);

    char const *pad = "";
    for (size_t i = 0; i < sizeof(my_union.data_array); i++)
    {
        printf("%sarray[%zu] = 0x%.2" PRIX8, pad, i, my_union.data_array[i]);
        pad = "; ";
    }
    putchar('\n');

    return 0;
}

产生显示的输出:

val_1 = 0xFEDC; val_2 = 0xBA; val_3 = 0x98
array[0] = 0xDC; array[1] = 0xFE; array[2] = 0xBA; array[3] = 0x98

这是我所期待的。你会在大端机器上获得不同的输出(除了英特尔以外的任何东西,或多或少)。

您需要调整此代码(或非常类似的代码)来演示您认为的任何问题,并显示修改后的代码和实际输出以及您对期望内容的解释以及您对不同输出的期望。

答案 1 :(得分:0)

这是明确错误的:

printf("Bytes of array:  %#08x\n", my_array.data_array);

您正在打印数组的第一个元素的地址,而不是内容,这是您感兴趣的内容。

无论如何,打印指针应该使用%p格式,所以一个不错的编译器应该给你一个警告。

要打印数组的内容,您必须打印它的每个元素。 uint8_t(不是unint8_t!)的正确格式说明符是宏PRIx8

答案 2 :(得分:0)

试试这个

printf("Bytes of struct: %#08x\n", *(uint32_t*)&my_union.data);
printf("Bytes of array:  %#08x\n", *(uint32_t*)my_union.data_array);