简体   繁体   中英

Union member data alignment

I'm having some problem with data alignment in a union, which I can't seem to figure out. Using a union similar to the one below, there seems to be some data offset at the union's base address.

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

At some point I've filled the struct in with data,

my_union.data.val_1 = 65535;
my_union.data.val_2 = 0;
my_union.data.val_3 = 0;

I then try to access the data using the array. What I expect to see at the base address of the array is the first byte of val_1, 255. However, when accessing the data in the array, it seems to be offset from the struct's base by 1 byte.

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

No matter what values I put in the above results in output similar to this.

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

I first thought that the members may be offset somehow and were referencing different memory address's, but when I print their addresses, they are the same.

Also, if I print the following values they are equal.

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

Output:

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

I'm sure I'm missing something simple, but I can't figure it out, at the moment. Thank you for any help in advance.

Run on a little-endian machine (Intel Core i7, Mac OS X 10.9.1 Mavericks, GCC 4.8.2), the following program:

#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;
}

produces the output shown:

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

This is very much what I'd expect. You'd get different output on a big-endian machine (anything but Intel, more or less).

You need to adapt this code (or something very similar) to demonstrate whatever problem you perceive you have, and show the modified code and the actual output and your explanation of what you expect and why you expect the different output.

This is definitively wrong:

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

you are printing the address of the first element of the array, instead of the contents, which is what seems to interest you.

Printing a pointer should use the %p format, anyhow, so a decent compiler should give you a warning.

To print the contents of the array, you'd have to print each element of it. The correct format specifier for uint8_t (not unint8_t !) is the macro PRIx8 .

try this

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM