C++ 为什么在Linux和Windows上使用gcc时,打包结构的大小会有所不同?

C++ 为什么在Linux和Windows上使用gcc时,打包结构的大小会有所不同?,c++,c,gcc,mingw,sizeof,C++,C,Gcc,Mingw,Sizeof,在下面的代码中,当使用gcc编译时,为什么Linux和Windows上的打包结构的大小不同 #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)

在下面的代码中,当使用gcc编译时,为什么Linux和Windows上的打包结构的大小不同

#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;
}
编译和测试:

$ 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属性第6.37.3节将其解释为ABI规范中的差异,请参见此处:

这是关于内存中的属性和单词对齐的

看看你有没有写信

struct header
{    
        uint8_t version[ 2 ];
        uint8_t flags;
        uint32_t size;
};
那么linux和windows的大小都是8

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

struct header
{    
        uint8_t version[ 2 ];
        uint8_t flags;
        uint32_t size;
} __attribute__((packed));
然后在linux中,由于attritube大小变为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. 

属性((打包))是特定于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( "%u\n", (unsigned int)sizeof( header ) );
        return 0;
}
#包括
#包括
//mp3文件的id3头文件
#pragma包(推送,1)
结构头
{    
uint8_t版本[2];
uint8_t旗;
uint32_t尺寸;
};
#布拉格语包(流行语)
int main(int argc,字符**argv)
{
printf(“%u\n”,(无符号整数)sizeof(头));
返回0;
}

结构将是7个字节。

GCC4.7.0
这样做是为了与64位MSVC++兼容。如果要正确打包结构,请使用
-mno ms位字段编译。(但是,您的布局将与MSVC++不兼容。)

更新。最新的MinGW很好用

g++(i686-win32-dwarf-rev0,由MinGW-W64项目构建)8.1.0和
g++(x86_64-win32-seh-rev0,由MinGW-W64项目构建)8.1.0

示例代码的prints sizeof()正好等于7个字节。

我猜该属性不知怎么被忽略了(因为一个bug)。使用
offsetof(header,size)
来确定是否是这样。如果我直接从windows xp使用MinGW g++4.5.2编译它,它会打印7。32位的思想。结构大小变化是预期的,这就是为什么在编译域中不使用/传递结构是一个好主意。边注:依赖于特定结构成员对齐的任何C或C++代码(例如直接读写磁盘或网络结构)难闻……这听起来很糟糕。microsoft编译器允许您将成员打包到您喜欢的程度。请参阅:#MS编译器的pragma包。但在windows下使用mingw可以很好地编译它,OP似乎正在使用它,可能是因为编译器特定的
位无关紧要?重要的是关于ABI的引用。我已经补充说bcz用户将在windows中使用属性((打包))编译程序,windows编译器“windows编译器”不支持属性((打包))?OP指定他在linux和Windows上都使用GCC——MSVC不是Windows上唯一的编译器。
#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;
}