Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoiding structure padding in c using __attribute__((packed))

Tags:

c

struct

I am using __attribute__((packed)) to avoid struct padding. The below code is working fine, but when I add one more int member inside the struct the compiler pads my struct.

#include <stdio.h>

struct test {

    int x;
    char c1;
    char c2;
    char c3;
    char c4;
    char c5;
    // int d; Pads if I uncomment

} __attribute__((packed)) obj = {50,'X','Y','Z','A','B'}; 

int main ()
{
    struct test *ptr= &obj;
    char *ind = (char *) &obj;

    printf("\nLet's see what is the address of obj %d", ptr);
    printf("\n Size of obj is : %d bytes ", sizeof(obj));
    printf("\nAddress of x is %d", &ptr->x);
    printf("\nAddress of c1 is %d", &ptr->c1);
    printf("\nAddress of c2 is %d", &ptr->c2);
    printf("\nValue  of x is %d", ptr->x);
    printf("\nAddress of x is %c", ptr->c1);
    printf("\nFetching value of c4 through offset %c", *(ind+7));

}

The above code is working as expected and the size of obj is 9 bytes (with padding it was 12 bytes).

However, when I uncomment int d in my struct the code outputs:

Size of obj is : 16 bytes

instead of the expected 13 (9 + 4) bytes.

What's wrong?

like image 998
theartist33 Avatar asked Aug 14 '15 15:08

theartist33


1 Answers

In structures there are two types of padding involved. (1) Padding added to make the structure a multiple of a certain number (In your case the size of int) and (2) Padding added to position certain data types at an address divisible by certain number. For example, 4 bytes for int. So in your case while compiler is happy to remove the first type of padding I think it is still forcing the member int d to an address divisible by 4. Since there are 5 chars before d, 3 bytes padding is added to force d to an address divisible by 4.

So try moving the member int d above the chars. Then of course you have to change the offset used in fetching value of c4 through offset. You can even put it right above c5. Then you wouldn't have to change your fetching value of c4 through offset line. Example:

struct test {

    int x;
    int d;
    char c1;
    char c2;
    char c3;
    char c4;
    char c5;

} __attribute__((packed)) obj = {50,'X','Y','Z','A','B'}; 

OR

struct test {

    int x;
    char c1;
    char c2;
    char c3;
    char c4;
    int d;
    char c5;

} __attribute__((packed)) obj = {50,'X','Y','Z','A','B'}; 
like image 145
MiJo Avatar answered Oct 18 '22 23:10

MiJo