How to tell gcc to disable padding inside struct?

2020-04-05 08:22发布

问题:

I’m unsure on whether it’s normal or it’s a compiler bug but I have a C struct with lot of members. Among of them, there’s, :

struct list {
    ...  
    ...
    const unsigned char nop=0x90; // 27 bytes since the begining of the structure
    const unsigned char jump=0xeb; // 28 bytes since the begining of the structure
    const unsigned char hlt=0xf4; // 29 bytes since the begining of the structure
    unsigned __int128 i=0xeb90eb90eb90eb90f4f4 // should start at the 30th byte, but get aligned on a 16 byte boundary and starts on the 32th byte instead
    const unsigned char data=0x66; // should start at the 46th byte, but start on the 48th instead.
}; // end of struct list.

I had a hard time to find out why my program wasn’t working, but I finally found there’s a 2 bytes gap between hltand i which is set to 0x0. This means that the i is getting aligned.
This is very clear when I printf that part of the structure, because with :

for(int i=28;i<35;i++)
    printf("%02hhX",buf[i]);

I get EBF40000EB90EB90 on the screen.

I tried things like volatile struct list data;in my program, but it didn’t changed the alignment problem.

So is there a #pragma or a __attribute__to tell gcc to not align i inside struct listtype ?

回答1:

In GCC you can use __attribute__((packed)) like this:

// sizeof(x) == 8
struct x
{
    char x;
    int a;
};

// sizeof(y) == 5
struct y
{
    char x;
    int a;
} __attribute__((packed));

See doc.

Also if you rely on the addresses of struct fields, take a look at the offsetof macro. Maybe you don't need to pack the structure at all.



回答2:

As touched on by @Banex

#pragma pack(push,1)
struct
{
        char a;
        int b;
        long long c;
} foo;
#pragma pack(pop)

The #pragma pack(push,1) pushes the current packing mode internally, and sets packing to 1, no padding

The #pragma pack(pop) restores the previous packing

Supposedly compatible with Microsoft's syntax

http://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/Structure_002dPacking-Pragmas.html



回答3:

The fields within the struct are padded in an implementation defined manner.

That being said, fields are typically aligned on an offest which is a multiple of the size of the data member (or array element if the member is an array) in question. So a 16 bit field starts on a 2 byte offset, 32 bit field starts on a 4 byte offset, and so forth.

If you reorder the fields in your struct to adhere to this guideline, you can typically avoid having any internal padding within the struct (although you may end up with some trailing padding).

By putting the fields at the proper offset, there can be performance gains over forcefully packing the struct.

For more details, see this article on structure packing.

While using the above techniques are not guaranteed, they tend to work in most cases.