Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoiding Structure Padding in C

Tags:

c

How we can avoid structure padding in C apart from using pragma pack aur bit field? Is there any other method available?

like image 315
user1837915 Avatar asked Nov 20 '12 06:11

user1837915


2 Answers

Pack the biggest items at the start of the structure. Pack smaller items towards the end.

struct optimal_packing
{
     double d;
     int    i[4];
     short  j[3];
     char   s[24];
};

To be slightly more accurate, it is the items with the most stringent alignment requirements that need to come earliest (which tend to be pointers and double or perhaps long double), and those with less stringent alignment requirements at the end (short and char). You can still end up with tail padding if the total length of the components adds up to, say 35 bytes, but one of the types requires an 8-byte alignment; there'd be 5 bytes of padding.

like image 150
Jonathan Leffler Avatar answered Oct 18 '22 13:10

Jonathan Leffler


The only completely portable and reliable way to avoid structure padding is not to use real members in your struct at all. Use a single char array member, and define macros that access its contents:

struct paddingless {
    // char *p;
    // double d;
    // char c;

#define OFFSET_P 0
#define OFFSET_D (OFFSET_P + sizeof(char *))
#define OFFSET_C (OFFSET_D + sizeof(double))    
#define OFFSET_END (OFFSET_C + sizeof(char))    

    char data[OFFSET_END];
};

Portable getters and setters would look like this:

inline double paddingless_get_d(const struct paddingless *o) {
    double val;
    memcpy(&val, o->data + OFFSET_D, sizeof(val));
    return val;
}
inline void paddingless_set_d(struct paddingless *o, double val) {
    memcpy(o->data + OFFSET_D, &val, sizeof(val));
}

If you know that your architecture accepts unaligned access, you can get away with a setter being defined with a cast:

#define paddingless_get_d(o) (*(double *) ((o)->data + OFFSET_D))
#define paddingless_set_d(o, val) (*(double *) ((o)->data + OFFSET_D) = (val))

This is non-portable, but potentially faster than the alternative. And it works on a vax x86...

like image 21
user4815162342 Avatar answered Oct 18 '22 13:10

user4815162342