typedef struct _C
{
char a;
int b;
char c;
}C;
这是因为x86系统下,结构体会发生内存对齐操作,这是为了cpu存取数据速度快而设定的。
在上述的结构体中,块头最大的是int b,占4个字节,所以整个结构体就占4个字节。
typedef struct _D
{
char a;
double b;
char c;
}D;
而上面的结构体根据块头最大原则,就是得出sizeof(D)=24。呵呵,实际上的程序也证实了这一点。
对于我遇到的结构体,具体定义如下:
typedef struct tagBITMAPFILEHEADER {
} BITMAPFILEHEADER;
这个结构体实际的大小是2+4+2+2+4=14.而默认的时候,x86系统由于有内存对齐的操作,所以给他分配了4+4+(2+2)+4=16 bytes的大小,用sizeof(BITMAPFILEHEADER)=16可以证实这一点。但是问题就在这里,实际上bmp文件中,上述结构的大小为14bytes,如果按照下面的函数读取的话,就会发生错误。
fs.read((char*)&bitmapFileHeader,sizeof(BITMAPFILEHEADER))
就会发生错误,这是为什么呢?下面自习分析这个数据结构:
typedef struct tagBITMAPFILEHEADER {
} BITMAPFILEHEADER;
在内存中分配的块如下:
我们可以看到,第3,4字节是为了内存对齐给添加进去的,我们依次把14B的文件头信息添加到这里的话,就会使数据发生错位。另外,如果读取16B的话,那么就会读取到不应该读取的内容。
影响到文件指针的定位,和后面的读取。这就是我把wingdi.h中的BITMAPFILEHEADER结构体直接copy到我文件中不能使用的原因。为了查明这个原因,我仔细的看了wingdi.h文件,发现它在这个结构体定义的前后有#include <pshpack2.h>和#include <poppack.h>,查看这这些文件,才知道pshpack2.h实际上就是让结构体按照2B的大小对齐,而poppack则是上一个对于pack的设置失效。内部实际上是有一个栈在维护这个东鳌?/p>
于是我把自己的结构体前后也加上了#include <pshpack2.h>和#include <poppack.h>,发现一切OK了。呵呵,大功告成。
后来我又发现,还有pshpack1.h,pshpack4.h,pshpack8.h等文件,如果include的话,就表示要按照1B,4B,8B的字节顺序对齐。(实际上是这里指定的值和结构体中块头最大的值,两者取最小值)。
比如
#include <pshpack4.h>
typedef struct _B
{
char a;
short b;
char c;
}B;
对于上述的机构体,其大小仍然是6.仍然是按照2B的大小对齐的。
另外查阅pshpack1.h等文件,发现对于结构体内存对齐的控制是通过如下的pragma指令来实现的。
所以,也可以直接在程序中用下面的指令,但是推荐使用include头文件的方法。
#pragma ack(push,n)//n=1,2,4,8
#pragma pack(pop)
#pragma pack(n)
#pragma pack()
另外,这样的操作是使得速度有所下降。所以不要滥用。