http://blog.csdn.net/lqk1985/archive/2008/10/23/3129976.aspx
对于读取数据流时(如网络或文件)要特别注意。
比如
PBYTE pData;
//指向接收到的数据流
int * pi = pData + 这次接收到数据流的大小 - 4;
//指向接收到数据流的最后4位,可能客户端发过来的这个数据流最后4位是int,那样就是对齐好的了。也有可能不是int。
if *pi = 4561321 endparse data;//判断作为数据流的结束标志,最后4位的前面可能是全是char的。
由于这最后4位可能不是int,那样就有可能不对齐,这里就会出现Datatype misalignment错误。但是我们还是必须通过最后4位作为结束标志,而只有知道什么时候结束才能用int指针指向最后4位才不会出现对齐错误。这样形成了一个死循环,难道没办法解决了么?
PBYTE pData;
PBYTE * pi = pData + 这次接收到数据流的大小 - 4;
int i;
memcpy(&i, pi, 4);
if i = 4561321 endparse data;
这样就可以解决用int* pi指向未对齐的int错误了。
这一招对所有碰到Datatype misalignment的数据的访问应该都有效,就是把Datatype misalignment的数据用memcpy拷贝到对齐的内存来访问。
1,解析数据流时应该时刻注意。如果需要把一个数据流(BUFFER)转化成结构进行取值,就应该把这个结构定义为按字节存取.考虑如下结构:
struct a{
char a;
short b;
long c;
};
如果某个数据流中包含这样的结构,而且我们要直接将数据流的指针转化成该结构的指针,然后直接取结构成员的值,我们就应该将这个结构定义成按字节访问,即将其夹在语句
#pragma pack(push,1)//设为1字节对齐
...
#pragma pack(pop)//还原为原来的字节对齐方式
之中。如果我们不这样做,编译器会将成员b的地址对齐到short指针的地址,即在a之后加上一个char即8位的成员,将C对齐到LONG,即在B之后再加一个char成员。如此一来,成员B和成员C就得不到正确的值了。
pragma pack 只作用于结构的定义,而不是分配内存空间。把一个结构定义为pack1后,这个结构在程序中就一直是1了。
上面这个例子是客户端发送3个连续的数据不是发送结构体,服务端接收结构体。
如果客户端也发送结构体,服务端也接收结构体就不需要这样了。但是前提是双方的对齐方式一致。所以在客户端发送前也要用#pragma pack()一下,服务端也要#pragma pack()一下。
最好还是客户端也单个数据发送,服务端也单个数据接收。
如果我们定义一个普通的结构用来存放一些数据,则不用定义成按字节存取,编译器会加上一些占位成员,但并不会影响程序的运行。从这个意义上讲,在ARM中,将结构成员定义成CHAR和SHORT来节约内存是没有意义的。
一个典型的例子就文件系统的驱动程序,文件是以一些已经定义好的结构存放在存储介质上的,它们被读取到一个BUFFER中,而具体取某个文件、目录结构时,我们会将地址转化成结构而读取其中的值。
2,访问外设时。
例如,磁盘驱动通常以16BIT的方式存取数据,即每次存取两个字节,这样就要求传给它的BUFFER是双字节对齐的,驱动程序应该至上层传来的指针做出正确的处理以保证数据的正确性。
3.有时,我们没有将数据流指针转化为结构指针取值,但如果我们读取的是双字节或者是四字节的数据,同样需要注意对齐的问题,例如,如果从一个BUFFER的偏移10处读取一个四字节值,则实际得到的值是偏移8处的
地址上的DWORD值。