C++读写BMP文件头部时的字节对齐问题

            今天用C++BMP文件头部时发现读出的数据与BMP中的内容不相同,经过查阅资料,才明白是结构体的字节对齐问题,内存和文件中的结构体都存在字节对齐问题。现总结一下。关于sizeof的计算可参考下面这篇文章:

http://fancyxinyu.blog.163.com/blog/static/1823213662011102161752137/

首先看字节对齐问题,测试程序如下:

#include
using namespace std;

void main()
{
	struct HEAD{
	unsigned short Type;
	unsigned int   Size;
	unsigned short Reserved1;
	unsigned short Reserved2;
	unsigned int   OffBits;
	};
	HEAD a,b;
	a.Type=0x4d42;
	a.Size=1024;
	a.Reserved1=0;
	a.Reserved2=0;
	a.OffBits=256;
	FILE* file;
	file=fopen("test.txt","wb");
	fwrite(&a,sizeof(HEAD),1,file);
	fclose(file);
	file=fopen("test.txt","rb");
	fread(&b,sizeof(HEAD),1,file);
	fclose(file);
	cout<

命令窗口中的运行结果如下:


查看二进制文件的结果如下:

       通过二进制文件看到变量Type在文件中实际存储为十六进制的42 4d cc cc,即存储文件时为了进行字节对齐,VC在Type的高16位自动添加了十六进制的数据cc cc。由命令窗口输出的结果知,写入的数据a与输出的数据b相同。

内存中也存在字节对齐。由于b.Type占两个字节,采用小端存储,因此将42 4d cc cc高两位字节截断后b.Type便为十六进制的4d 42,用十进制表示即为19778。通过上面的分析也可知sizeof(HEAD)不为14,而是16个字节。16=14+2。其中的2是由于Type占两个字节,Size的偏移量要为4的倍数,因此在Type的高位由VC自动填充两位。(参见本文开头的链接)

现在来看一个BMP文件的内容,部分数据如下:


将此数据通过与BMP头文件的数据结构比较,可知BMP头文件中没有采用字节对齐方式。因此不能直接把数据读入HEAD中。否则由于存入HEAD中的BMP文件数据没有字符对齐,而对结构体中的变量赋值时存在字节对齐,这样便会使读入的数据丢失和错位。发现有很多用C++读BMP文件的程序都是直接用fread读数据,自己也尝试过这种方法,但是发现读的数据不正确。解决这个问题的一个比较笨的办法是把bmp文件中的数据一个一个读出,然后赋给变量中的对应元素。还有一种简便的方法,就是所定义的BMP位图头文件中不要包含Type变量。现在来分析一下。除过Type变量后相邻字节均对齐(参见开头链接),另外结构体的总字节数为4+2+2+4=12,是最大字节长度的整数倍,因此不需再填充字节,可以利用fread直接读取文件的块数据。最简单的方式是是设定编译器的字节对齐方式,即:

#pragma pack(push,1)
struct HEAD{
	unsigned short Type;
	unsigned int   Size;
	unsigned short Reserved1;
	unsigned short Reserved2;
	unsigned int   OffBits;
};
#pragma pack(pop)

你可能感兴趣的:(C++)