GCC syntax “__attribute__((packed))”

The keyword __attribute__ allows you to specify special attributes of variables or structure fields.
This keyword is followed by an attribute specification inside double parentheses.
This article is about __attribute__((packed)).
Without this keyword we can see certain problems we couldn’t expect. Let’s look at a really simple program below.

#include <stdio.h>
#include <string.h>

struct sample{
    int a;
    char b;
    double c;
};

int main(void) {
    int             result1;
    int             result2;
    struct sample   st1;
    struct sample   st2;

    st1.a = 1; st1.b = 'a'; st1.c = 3;
    st2.a = 1; st2.b = 'a'; st2.c = 3;

    result1 = memcmp( &st1, &st2, sizeof(struct sample) );
    printf( "%d\n", result1 );

    st1.a = 2; st1.b = 2; st1.c = 3;
    st2.a = 1; st2.b = 2; st2.c = 3;

    result2 = memcmp( &st1, &st2, sizeof(struct sample) );
    printf( "%d\n", result2 );

    return 0;
}

Library function ‘memcmp()’ simply returns 0 if two memory fields have same value.
The structure st1 and st2 get same value first,  and different value later.
So we can expect that the results will be

0
1

however, the result prints

-1
1

Why this unexpected fault occurs? To see this, a new function is added.

#include <stdio.h>
#include <string.h>

void memprint(const void *cs, const void *ct, size_t count)
{
    const unsigned char *su1 = cs, *su2 = ct, *end1 = su1 + count, *end2 = su2 + count;

    while (su1 < end1) {
        printf("%X", *su1++);
    }
    printf("\n");
    while (su2 < end2) {
        printf("%X", *su2++);
    }
    printf("\n");
}

struct sample{
    int a;
    char b;
    double c;
};

int main(void) {
    int             result1;
    int             result2;
    struct sample   st1;
    struct sample   st2;

    st1.a = 1; st1.b = 'a'; st1.c = 3;
    st2.a = 1; st2.b = 'a'; st2.c = 3;

    memprint( &st1, &st2, sizeof(struct sample) );

    return 0;
}

The newly inserted function ‘memprint’ simply prints hexadecimal values of two memory area.
Now we can see the contents of the memories of two structures.
The printed result is

100061FFFFFF000000840
1000612330000000840

It’s really weird. Why this happens?
Usually compilers let the structure variables be aligned so that the processors can work faster.
If you’re using a 32-bit processor, the variables in a structure will be aligned by 4 bytes.
And the rest of the memory will get some random values. As you see,
So SOMETIMES this unexpected pads will occur problems.

It can be corrected when we use __attribute__((packed)) keywords.
The final sample code would be like below:

#include <stdio.h>
#include <string.h>

void memprint(const void *cs, const void *ct, size_t count)
{
    const unsigned char *su1 = cs, *su2 = ct, *end1 = su1 + count, *end2 = su2 + count;

    while (su1 < end1) {
        printf("%X", *su1++);
    }
    printf("\n");
    while (su2 < end2) {
        printf("%X", *su2++);
    }
    printf("\n");
}

struct sample{
    int a;
    char b;
    double c;
};

struct sample2{
    int a;
    char b;
    double c;
}__attribute__((packed));

int main(void) {
    int             result1;
    int             result2;
    struct sample   st1;
    struct sample   st2;
    struct sample2  pst1;
    struct sample2  pst2;

    printf( "sizeof(struct sample): %d\n", sizeof(struct sample) );
    printf( "sizeof(struct sample2): %d\n", sizeof(struct sample2) );

    #warning /* this is the weird behavior - putting integer to char variable */
    st1.a = 1; st1.b = 'a'; st1.c = 3;
    st2.a = 1; st2.b = 'a'; st2.c = 3;
    pst1.a = 1; pst1.b = 'a'; pst1.c = 3;
    pst2.a = 1; pst2.b = 'a'; pst2.c = 3;

    result1 = memcmp( &st1, &st2, sizeof(struct sample) );
    memprint( &st1, &st2, sizeof(struct sample) );
    printf( "%d\n", result1 );

    result2 = memcmp( &pst1, &pst2, sizeof(struct sample2) );
    memprint( &pst1, &pst2, sizeof(struct sample2) );

The printed result is

sizeof(struct sample): 16
sizeof(struct sample2): 13
1000618648000000840
100061939E0000000840
-1
100061000000840
100061000000840
0

We can see that with __attribute__((packed)) keywords, the structure variables have no pads inside.
On the contrary, without the keyword, the structure variables have pads in the middle of them like

100061 8648 000000840
100061 939E 0000000840

Sometimes we need to PACK the structures with the keyword __attribute__((packed)) to overcome unexpected errors.
However, packing the structures causes much much much lower performance. It’s on the choice of developers.

Leave a comment