遭遇字节对齐的问题。


#include <vcl.h>
#pragma hdrstop
#include<stdio.h>
#include "Unit1.h"
#include"File1.h"


struct BITMAPFILEHEADER_
{

short type;
int bfSize;
short re1,re2;
int Offbits;
};

struct BITMAPINFO_
{
long size;
long width,height;
short planes,bitCount;
long comp,sizeImg;
long xpels,ypels;
long used,important;
};

struct COLORTABLE_
{
char blue,green,red,res;
};

void xxx()
{
FILE *f=fopen("F://projects//bmp//1.bmp","rb");
if(f==NULL) /*判断文件是否打开成功*/
{
ShowMessage("File open error");
return;
}
fseek(f,0,0);
BITMAPFILEHEADER_ *bmph=new BITMAPFILEHEADER_();
if(fgets((char*)bmph,sizeof(BITMAPFILEHEADER_),f)==NULL)
{
ShowMessage("File read error");
return;
}

BITMAPINFO_ *bmpi=new BITMAPINFO_();
if(fgets((char*)bmpi,sizeof(BITMAPINFO_),f)==NULL)
{
ShowMessage("File read error2");
return;
}

Form1->Edit1->Text=IntToStr(bmph->bfSize);
Form1->Edit2->Text=IntToStr(bmpi->width);
Form1->Edit3->Text=IntToStr(bmpi->height);

fclose(f);
};

 

这是一个用BCB写的普通的读取BMP文件头信息的简单程序,但工作不正常。

显示结果

Edit1:0

Edit2:1073741824

Edit3:16777216

苦思冥想解释不了,用Ultra edit打开BMP文件发现文件开头是

42 4D 38 14 00 00 00 00 00 00 36 04 00 00 28 00

文件是没错的,42 4D是BMP文件标志“BM”,接下来38 14 00 00 是文件大小,INT值是0X1438=5176字节,和WINDOWS显示的一样,没错。

后来写了个程序读出第一个自己‘B’和第2个字节‘M’却时正确的,就时到读size时会变成0,只能怀疑是BITMAPFILEHEADER_结构匹配数据时出了问题,为了进一步验证,写了另一个程序自己填充BMP文件头,写入磁盘,再用Ultra edit查看,程序代码是这样的。

#pragma argsused

#include<stdio.h>

#include<stdlib.h>

struct BITMAPFILEHEADER_
{

short type;
int bfSize;
short re1,re2;
int Offbits;
};

int main(int argc, char* argv[])
{
FILE *f=fopen( "f://abc.txt","wb");
BITMAPFILEHEADER_ *b=new BITMAPFILEHEADER_();
b->type=1;
b->bfSize=1;
b->re1=b->re2=1;
b->Offbits=1;

if(f==NULL)
{
printf("xxx");
system("pause");
return 0;
}

fwrite( b,sizeof(BITMAPFILEHEADER_),1,f);
system("pause");
return 0;
}

 

用Ultra Edit 查看发现居然写了 16 个字节,如下

01 00 67 32 01 00 00 00 01 00 01 00 01 00 00 00

写了 type 后无缘无故多了个 67 32,后面的又没问题,突然想起论坛上有讨论过C语言的字节对齐问题,就怀疑是字节对齐的问题,到网上找BCB字节对齐的指令,原来BCB默认是4字节对齐,用#pragma pack(1)可以把字节对齐设置到1字节。

加上#pragma pack(1),读出的数据就正确了。

奔腾机器是32位系统,数据总线宽度32位,CPU一次从内存传送4字节的数据,为了取一个数据时能把访问存储器的减到最少,编译器默认结构类型的数据以4字节对齐,这样读取上面那个BITMAPFILEHEADER_结构需要4次访问内存(16字节每次读4字节),跟在这个结构后面的数据也在内存中对齐了,如果后面再跟着一个BITMAPFILEHEADER_结构,那么读取后面那个BITMAPFILEHEADER_也只需要4次访问内存,如果用#pragma pack(1)强制1字节对齐后,访问第一个BITMAPFILEHEADER_时仍然时4次访问内存,但访问后面紧接着的那个BITMAPFILEHEADER_时就需要5次访问内存,而且再后面接着的数据也对不齐了。

虽然出于性能的考虑编译器默认4字节对齐,但有时用户用户有有自己的需要不对齐,就像上面那种情况,这时就要用IDE指令#pragma pack(1)强制不对齐了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值