为什么在Linux和Windows上使用gcc时,压缩结构的大小会不同?

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

本文关键字:结构 压缩 Linux Windows gcc 为什么      更新时间:2023-10-16

在下面的代码中,为什么在Linux和Windows上使用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( "%un", (unsigned int)sizeof( header ) );
        return 0;
}

使用的gcc版本:

$ 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)
编译和测试:
$ 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.

Linux二进制文件打印预期大小为7字节,Windows二进制文件打印8字节。为什么会有不同呢?

gcc 4.7.0这样做是为了与64位msvc++兼容。如果您想正确打包结构,请使用-mno-ms-bitfields进行编译。(但你的布局将与msvc++不兼容)

第6.37.3节的gcc属性解释了它在ABI规范中的不同,参见这里:http://gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html

属性((packed))是GCC特定于编译器的。因此,该代码甚至无法用msvc++编译。也许你使用了另一种Windows编译器。但是,使用msvc++,您可以这样做:

#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( "%un", (unsigned int)sizeof( header ) );
        return 0;
}

这是关于属性字对齐在内存

看你是否写

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

then Linux &Windows都是8

但是当你指定属性以避免默认的世界对齐时,

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

然后在Linux中因为属性大小变成了7

参见gcc规范中说

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. 

更新。最新的MinGW运行良好

g++ (i686-win32-dwarf-rev0, Built by MinGW-W64 project) 8.1.0g++ (x86_64-win32-seh-rev0, Built by MinGW-W64 project) 8.1.0打印样本代码的sizeof()正好等于7字节