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?

x-x
  • 7,287
  • 9
  • 51
  • 78
  • 1
    My guess is the attribute somehow gets ignored (because of a bug). Use `offsetof(header, size)` to find out if it's so. – cnicutar Oct 17 '11 at 05:26
  • 1
    If I compile it directly from windows xp with MinGW g++ 4.5.2, it prints 7. 32 bit though. – Vlad Oct 17 '11 at 05:28
  • struct sizes varying is expected, which is why it is a good idea to never use/pass structures across compile domains. – old_timer Oct 17 '11 at 05:28
  • @dwelch: not with packed attribute, thats what its for. – Daniel Oct 17 '11 at 05:30
  • If it's for an ID3 tag, I suppose the struct packing is part of the format, so no choice there. – Vlad Oct 17 '11 at 05:31
  • @DrTwox: you're aware you're using an experimental compiler for the second part, right? – Mat Oct 17 '11 at 05:47
  • 8
    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... – 6502 Oct 17 '11 at 05:48
  • 1
    Meh, it only sounds bad. – Hans Passant Oct 17 '11 at 09:05
  • @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. – old_timer Oct 17 '11 at 13:36

5 Answers5

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++.)

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
TonyK
  • 16,761
  • 4
  • 37
  • 72
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

Necrolis
  • 25,836
  • 3
  • 63
  • 101
  • 1
    The microsoft compiler lets you pack the members as tight as you like. See: #pragma pack for the MS compiler. – harper Oct 17 '11 at 05:40
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.

Amy
  • 1,814
  • 2
  • 23
  • 38
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. 
Jeegar Patel
  • 26,264
  • 51
  • 149
  • 222
  • 1
    Perhaps because the `compiler specific` bit does not matter ? What matters is the quote about ABI. – Matthieu M. Oct 17 '11 at 06:39
  • i have added that bcz user is going to compile program with attribute((packed)) in windows, attribute((packed)) is not supported in windows compiler – Jeegar Patel Oct 17 '11 at 06:48
  • 2
    "windows compiler"? OP specifies he uses GCC both on linux and Windows - MSVC isn't the only compiler around for Windows. – snemarch Oct 17 '11 at 08:21
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.

Alexey Esaulenko
  • 499
  • 2
  • 10