全部博文(1493)
分类:
2012-10-09 08:51:05
原文地址:指针和内存对齐在通信中的问题 作者:apple_guet
相关概念:
大端模式:数据的低位保存在内存的高地址中,而数据的高位保存在内存的低地址中,这种存储模式就类似把数据当做字符串顺序处理,例如:数据中两个字节按顺序为:FE 10 ,它表示的一个数就是0xFE10。
换句话说:内存的低地址存放着数据高位;
小端模式:数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中,这种存储方式就是将地址的高低和数据的位结合起来,前面的例子按照小端模式表示,应该为:0x10FE。
换句话说:内存的低地址存放着数据低位。
使用背景:
通信中数据是以字节形式传递的,而单片机中的数据种类有很多,char、int、long、数组、结构体,这些数据都需要转换为字节形式,按照通信协议的要求(高字节在前或低字节在前)进行发送。最基本的做法是使用未处理把每个字节分离,但这不是最好的办法,也不是常用的办法。常用的方法是使用指针。
使用实例:
从我的程序中举两个例子,之所以举这两个例子,是因为,在第二次使用时,我发现指针我还是没搞透,不过幸亏我了解自己,所以特意留意了这个问题,呵呵,不至于让他成为一个Bug。
例1.对传感器输出数据的调整
由于传感器输出的数据是MSB在前,LSB在后;而MSP430的内存为 ”小端模式“,所以需要进行内存调整。搞明白了这个还需要搞明白怎样使用指针来进行内存交换。
这里 int XYZ_RoughVal [3] = {0}; //是一块连续的内存。
那么表达式 (u8)*((u8*)XYZ_RoughVal+j) 就可以取到这块内存中第j个字节的值,分析:
XYZ_RoughVal :数组地址,一个指针,类型为 int*,指向int数据
(u8*)XYZ_RoughVal :把地址指针转换为 u8* 类型,使得指针指向字节
(u8*)XYZ_RoughVal+j :第j个元素的地址
*((u8*)XYZ_RoughVal+j) :第j个元素的值
(u8)*((u8*)XYZ_RoughVal+j) :强制转换为 u8
例2.把一个int型数据写入发送缓冲
int CarInfo = 0;
同样,协议要求MSB在前,但是MSP430为小端对齐,所以需要取得int数据中每个字节的值。而与数组不同的是,如果使用 *((u8*)CarInfo+1) 表达式,结果是错误的。为什么?
来分析下,CarInfo 是一个int数据, 那么 (u8*)CarInfo 是一个u8* 类型指针,但他指向的地址是 CarInfo 的值所表示的地址,譬如CarInfo内存地址为0×248,值为0×101,那么 (u8*)CarInfo指向的地址是 地址0×101,而地址0×101中存放的数据是0x0B。这就错了。
正确的表达式应该是 *((u8*)&CarInfo+1) ,分析: &CarInfo:CarInfo的地址; (u8*)&CarInfo:把这个地址转换为 u8* 类型。
小结:
指针是非常高效的,内存对齐是值得注意的。