C语言结构体中的对齐问题

最近上一门名为《数字图像处理》的课程,今天打算做一个小实验:将一张BMP图像的每一个像素都置换成相补的颜色值(255-当前像素值)。题目很简单,为阅读相关网页,了解了一下BMP图像头的相关信息,定义了如下结构体:

typedef  struct  BITMAPFILEHEADER
{
    short int  bfType;         //位图文件的类型,必须为BM
    long       bfSize;         //文件大小,以字节为单位
    short int  bfReserverd1;   //位图文件保留字,必须为0
    short int  bfReserverd2;   //位图文件保留字,必须为0
    long       bfbfOffBits;    //位图文件头到数据的偏移量,以字节为单位
}BITMAPFILEHEADER;


typedef  struct  BITMAPINFOHEADER
{
    long        biSize;                 //该结构大小,字节为单位
    long        biWidth;                //图形宽度以象素为单位
    long        biHeight;               //图形高度以象素为单位
    short int   biPlanes;               //目标设备的级别,必须为1
    short int   biBitcount;             //颜色深度,每个象素所需要的位数
    long        biCompression;          //位图的压缩类型
    long        biSizeImage;            //位图的大小,以字节为单位
    long        biXPelsPermeter;        //位图水平分辨率,每米像素数
    long        biYPelsPermeter;        //位图垂直分辨率,每米像素数
    long        biClrUsed;              //位图实际使用的颜色表中的颜色数
    long        biClrImportant;         //位图显示过程中重要的颜色数
}BITMAPINFOHEADER;


typedef  struct BITMAP
{
    BITMAPFILEHEADER  file;    //文件信息区
    BITMAPINFOHEADER  info;    //图象信息区
}BITMAP;

(注:结构体的定义参考了http://blog.youkuaiyun.com/courage89/article/details/7187255和http://blog.youkuaiyun.com/zhaozidong86/article/details/6628469)


BMP的图像头大小为54字节(十六进制36H)。为了防止出错(其实是第一次的测试结果有点不正常),我仔细查看了一下结构体定义的准确性。


结果出人意料:


可以自习数一下上面结构体的定义,BITMAPFILEHEADER的字节数应该是0DH,而不应该是10H。

为什么会出现这种情况呢?

我的猜想是结构体内部存在对齐。换句话说,编译器为了物理结构上处理的方便,在结构体内部空余了部分位置。由于结构体中只有2字节和4字节数据,最可能的就是四字节对齐。

为此,我将BITMAPFILEHEADER稍作改变:

结果是:

可以看见,我在2(+2)+4+2+2的本已对齐的基础上多添加一个大小为2字节的字段,结构体的总大小却增加了4字节。这个结果证实了我的想法。

为了进一步证实我的想法, 我又对这个结构体做了如下修改:

现在结构体的字段变成了2+2+4+2+2+4的已对齐的格式,我的猜想是其字节大小为10H。结果如下:

实验的结果跟预测结果是吻合的。


那么,结论是,C语言结构体在内部确实存在对齐规则。


上述实验是在Codeblocks 12.11环境下进行的,编译器是CB默认的GNU-GCC。那么在WIndows的VC环境下,是不是有同样的结果呢?

以下分别是上述情况的运行结果:


可见,VC的结构体内部也是存在对齐规则的。


结构体内部对齐的好处是编译器更为方便的内存管理,但这种编译器的自动优化,却给程序设计者带来很多问题。带给我最直接的问题是,我不能通过

这种简单的方式读取图像的文件头和信息头数据。


那么该如何改进呢?当然对结构体的每个字段都单独读取是可行的,这样会添加不少几乎重复的代码,却是一个百试百灵的绝招。另一个针对本次实验特定问题的处理方法是,首先对没有对齐的数据单独读取内容(本实验中,只有BITMAPFILEHEADER),对剩下的内容小心设置每次读取数据的数量,即可险中求胜。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值