对齐目的:sizeof结构体大小
为了简化硬件设计和提高内存效率,编译器对程序中的变量存储地址进行了对齐。比如一个int在32位机器上,总线读取的地址如果为4的倍数,
一个周期能够读取32bit的数据,如果int不按照4byte对齐,则需要两个周期才能够读取,而对齐之后只需要一个周期就可以读出。
对齐方式
linux 32平台下默认对齐方式为:
1. char 按照字节对齐
2. short 按照2字节对齐
3. int,long等其他基本类型按照4字节对齐
4. 为了保持结构体的对齐,对于结构体中元素,需要在元素之间插入gap,以满足每一个元素的自己的对齐要求。
5. 为了让结构体数组中的每一个结构体内部元素都保持对齐,编译器会在结构体的末尾插入gap以满足结构体内部元素的对齐要求。结构体的地址对齐按照结构体中包含的最大字节数元素对齐,以满足结构体数组的对齐要求。
EXAMPLE:
struct P1 { char a; int b; char c;}; sizeof(P1) = 12;
struct P1 { char a; short b; char c;}; sizeof(P2) = 6;
P1 p[2]; 这样p[0]和p[1]中的每一个元素都满足了对齐要求。
struct P1 { int i; char c; int j; char d}; sizeof(P1) = 16;
struct P1 { int i; char c; char d; int j}; sizeof(P1) = 12;
struct P1 { short w[3]; char c[3] }; sizeof(P1) = 10;
linux 64位平台下默认对齐方式和32位平台类似.
关于64位平台使用32位平台二进制数据
结构体以二进制形式从32位平台被写入文件,这时文件中的数据布局和结构体在内存中的布局是相同的.在64位平台下,结构体的内存布局可能因为对齐的原因发生变化,比如:在adserver中的cind1结构在32平台下的大小为28bytes,但是在64位平台下为40bytes;
对于跨平台的读取,不能够采用32平台下的方法直接以二进制的方式读取文件.在64位平台上使用32平台的数据时,首先:
1.明白32位平台下结构体的二进制数据在内存中的布局。
2.在64位下构造相关结构体将数据读出,然后做数据转化。
如果32位平台下和64位平台下内存布局相同,只是尾部不同,也可以将数据以结构体为单位一个一个的读出,然后对尾部数据进行单独处理。
在迁移adserver的过程中曾犯过的错误
如果某个结构体在32位平台下和64位平台下结构体内存布局只有末尾不同,不能采用如下的方式正确读出数据。
比如:
struct Sdata_t
{
int a; int b; int *p;
};
Sdata_t data[10];
32 写:
fwrite( data, sizeof(Sdata_t), 10, fp );
64 读:
fread( data, 12, 10 ,fp );
使用上面的读写操作,数据是不能正确读出的,因为64位下sizeof(Sdata_t)位16byte,采用上面的方法读数据,第二次读会将data[0]的尾部内存空间的数据覆盖掉,以此类推。
上面读取的是Sdata_t的数组,如果只是读一个Sdata_t的对象,上面方法能够将数据部分正确读出。
由此可以推知fread的工作方式,读10次,每次12byte,将读入的数据顺序填入以&data 开始的内存中。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论