2006年9月15日

struct内部成员对齐带来的问题

24位的bmp文件的头部信息是由如下的两个结构组成的。共54字节


struct SBitMapFileHeader
{
unsigned short bfType; // 位图文件的类型,必须为BM
unsigned long bfSize; // 位图文件的大小,以字节为单位
unsigned short bfReserved1; // 位图文件保留字,必须为0
unsigned short bfReserved2; // 位图文件保留字,必须为0
unsigned long bfOffBits; // 位图数据的起始位置,以相对于位图

};


struct SBitMapInforHeader
{
unsigned long biSize;
long biWidth;
long biHeight;
unsigned short biPlanes;
unsigned short biBitCount;
unsigned long biCompression;
unsigned long biSizeImage;
long biXPelsPerMeter;
long biYPelsPerMeter;
unsigned long biClrUsed;
unsigned long biClrImportant;

};

拿第一个struct做例子吧,用printf("%d",sizeof(SBitMapFileHeader));看一下大小是16字节。
三个unsigned short,两个unsigned long加起来是14字节,因为为了内存对齐,第一个unsigned short占了4个字节的内存区域。(实际用于存储的还是两个)。bmp里仍然是用14个字节来存储。所以fread(&mapHeader , 1 , sizeof(SBitMapFileHeader), pMapFile);的读取办法就会出错。(在VS.NET 2003和Dev C++是如此的)。
一种写法:

fread(tmp_head, 14, 1, fp_load); /* 此处用中转空间tmp_head */
file_header.bfType = tmp_head[0];
file_header.bfSize = (0xffff0000 & ((unsigned long)tmp_head[2] << 16) |
0x0000ffff & ((unsigned long)tmp_head[1]));
file_header.bfReserved1 = tmp_head[3];
file_header.bfReserved2 = tmp_head[4];
file_header.bfOffBits = (0xffff0000 & ((unsigned long)tmp_head[6] << 16) |
0x0000ffff & ((unsigned long)tmp_head[5]));

我看了觉得不爽,不够透明。写了这个:

fread(&mapHeader.bfType , 1 , sizeof(unsigned short) , pMapFile);
fread(&mapHeader.bfSize , 1 , sizeof(unsigned long ) , pMapFile);
fread(&mapHeader.bfReserved1 , 1 , sizeof(unsigned short) , pMapFile);
fread(&mapHeader.bfReserved2 , 1 , sizeof(unsigned short) , pMapFile);
fread(&mapHeader.bfOffBits , 1 , sizeof(unsigned long ) , pMapFile);

豆豆看了又觉得不爽,写了这个:

#pragma pack(1)
struct SBitMapFileHeader
{
unsigned short bfType; // 位图文件的类型,必须为BM
unsigned long bfSize; // 位图文件的大小,以字节为单位
unsigned short bfReserved1; // 位图文件保留字,必须为0
unsigned short bfReserved2; // 位图文件保留字,必须为0
unsigned long bfOffBits; // 位图数据的起始位置,以相对于位图

};
#pragma pack(4)

这样编译器就不会默认用4个字节对齐了,VS.NET 2003,W4(Warning 4)等级下有一个warning.不过已经是很完美的方案了。

没有评论: