简体   繁体   中英

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

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?

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

Thanks to all who took time for getting into peculiarities .I would like to tell the behavior of compiler which I am using after doing different checks and would like to stick to the fact that in both scenario ie with and without padding compiler wants integer member to fall on the address which is divisible by it's size, in this case 4 bytes,(pads in between) which although does not define 'use of attribute' functioning however still serve good purpose .As we know and I assume compiler rightfully more emphasize on speed instead of space and thus want to save time in performing instruction and saving machine cycle . Strictly Following above protocol, if compiler presumes that next member which it encounters is integer then it is best condition because then compiler won't have to worry about padding or no padding because next integer is definitely going to fall on address divisible by 4 (bytes) . It is even better if double is size of 4 bytes as in linux 32 bit arch . One thing I can assure is, in case of no padding (making use of attribute) compiler is avoiding pads at the end but in case of padding compiler pads bytes in between as well as at the end to make whole structure size divisble by 4.(because struct size which is divisble by 8 (double size on some machine) is divisible by 4 as well ).As question and functioning is totally compiler based so it wasn't fair to everyone that's why even more thanks.

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