Why would the size of a packed structure be different on Linux and Windows when using gcc?
Asked Answered
S

5

18

In the code below, why is the size of the packed structure different on Linux and Windows when compiled with gcc?

#include <inttypes.h>
#include <cstdio>

// id3 header from an mp3 file
struct header
{    
        uint8_t version[ 2 ];
        uint8_t flags;
        uint32_t size;
} __attribute__((packed));

int main( int argc, char **argv )
{
        printf( "%u\n", (unsigned int)sizeof( header ) );
        return 0;
}

gcc versions used:

$ g++ --version
g++ (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2
$ x86_64-w64-mingw32-g++ --version
x86_64-w64-mingw32-g++ (GCC) 4.7.0 20110831 (experimental)

Compile and test:

$ g++ -Wall packed.cpp -o packed && ./packed
7
$ x86_64-w64-mingw32-g++ -Wall packed.cpp -o packed.exe
--> prints '8' when run on Windows.

The Linux binary prints the expected size of 7 bytes, the Windows binary 8 bytes. Why the difference?

Shuttle answered 17/10, 2011 at 5:21 Comment(9)
My guess is the attribute somehow gets ignored (because of a bug). Use offsetof(header, size) to find out if it's so.Roundhead
If I compile it directly from windows xp with MinGW g++ 4.5.2, it prints 7. 32 bit though.Marginate
struct sizes varying is expected, which is why it is a good idea to never use/pass structures across compile domains.Phratry
@dwelch: not with packed attribute, thats what its for.Middlebrooks
If it's for an ID3 tag, I suppose the struct packing is part of the format, so no choice there.Marginate
@DrTwox: you're aware you're using an experimental compiler for the second part, right?Yardstick
Side note: Any C or C++ code that relies on specific struct member alignment (e.g. reading or writing structures directly to disk or network) smells bad...Arborvitae
Meh, it only sounds bad.Adjustment
@Dani except that it is not universal and universally does not work. it is just a bad idea. 6502 obviously said it in a better way than I did. smells, bad, sounds bad, etc.Phratry
P
4

Section 6.37.3 of the gcc attributes explains it as a difference in ABI specs, see here: http://gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html

Prognostic answered 17/10, 2011 at 5:33 Comment(1)
The microsoft compiler lets you pack the members as tight as you like. See: #pragma pack for the MS compiler.Keesee
V
7

gcc 4.7.0 does it this way to be compatible with 64-bit MSVC++. If you want to pack the structure properly, compile with -mno-ms-bitfields. (But then your layout will be incompatible with MSVC++.)

Visitation answered 17/10, 2011 at 8:15 Comment(0)
P
4

Section 6.37.3 of the gcc attributes explains it as a difference in ABI specs, see here: http://gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html

Prognostic answered 17/10, 2011 at 5:33 Comment(1)
The microsoft compiler lets you pack the members as tight as you like. See: #pragma pack for the MS compiler.Keesee
G
3

The attribute((packed)) is compiler-specific to GCC. Hence, that code won't even compile with MSVC++. Maybe you used another compiler for Windows, though. However, with MSVC++ you could do this:

#include <stdint.h>
#include <cstdio>

// id3 header from an mp3 file
#pragma pack(push,1)
struct header
{    
        uint8_t version[ 2 ];
        uint8_t flags;
        uint32_t size;
};
#pragma pack(pop)

int main( int argc, char **argv )
{
        printf( "%u\n", (unsigned int)sizeof( header ) );
        return 0;
}

and the struct will be 7 bytes.

Gilles answered 17/10, 2011 at 5:49 Comment(1)
But it'll compile just fine using mingw under windows, which it appears the OP is usingPrognostic
H
1

This is all about attribute and word alignment in memory

see if you write

struct header
{    
        uint8_t version[ 2 ];
        uint8_t flags;
        uint32_t size;
};

then linux & windows both have size 8

but when you specify attribute to avoid default world allignment then

struct header
{    
        uint8_t version[ 2 ];
        uint8_t flags;
        uint32_t size;
} __attribute__((packed));

then in linux because of attritube size becomes 7

see gcc spec says that

If packed is used on a structure, or if bit-fields are used 
it may be that the Microsoft ABI packs them differently than 
GCC would normally pack them. 
Haversine answered 17/10, 2011 at 5:41 Comment(3)
Perhaps because the compiler specific bit does not matter ? What matters is the quote about ABI.Religiosity
i have added that bcz user is going to compile program with attribute((packed)) in windows, attribute((packed)) is not supported in windows compilerHaversine
"windows compiler"? OP specifies he uses GCC both on linux and Windows - MSVC isn't the only compiler around for Windows.Planking
V
0

Update. Latest MinGW works fine.

Both g++ (i686-win32-dwarf-rev0, Built by MinGW-W64 project) 8.1.0 and g++ (x86_64-win32-seh-rev0, Built by MinGW-W64 project) 8.1.0 prints sizeof() of sample code is exactly equal 7 bytes.

Vogeley answered 20/12, 2018 at 11:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.