读取数据与地址对齐
在chinaunix呆久了,便想在这里记录一些想法,也整理一下以前零散的记录,希望能和大家共进步。此篇文章也作为开博第一回吧。
今天翻看一本书,看到了代码移植需要注意的若干问题,其中提到数据对齐,让我想起遇到的x86和ARM平台一些小区别。
有时候我们需要强制转换类型以便得到我们期望的数据,例如
char data[10]= {1,2,3,4,5,6,7,8,9,0}; unsigned int d[4]; d[0] = *(unsigned int *)&data[0]; |
在linux内核中有get_unaligned()宏定义,让你跨平台时使用。此函数有什么作用呢?
我们不妨来看看它的定义:
asm-i386/unaligned.h: #define get_unaligned(ptr) (*(ptr)) |
asm-arm/unaligned.h: 183 #ifndef __ARMEB__ 184 #define get_unaligned __get_unaligned_le 185 #define put_unaligned __put_unaligned_le 186 #else 187 #define get_unaligned __get_unaligned_be 188 #define put_unaligned __put_unaligned_be 189 #endif |
再看__get_unaligned_le:
54 #define __get_unaligned_le(ptr) \ 55 ({ \ 56 __typeof__(*(ptr)) __v; \ 57 __u8 *__p = (__u8 *)(ptr); \ 58 switch (sizeof(*(ptr))) { \ 59 case 1: __v = *(ptr); break; \ 60 case 2: __v = __get_unaligned_2_le(__p); break; \ 61 case 4: __v = __get_unaligned_4_le(__p); break; \ 62 case 8: { \ 63 unsigned int __v1, __v2; \ 64 __v2 = __get_unaligned_4_le((__p+4)); \ 65 __v1 = __get_unaligned_4_le(__p); \ 66 __v = ((unsigned long long)__v2 << 32 | __v1); \ 67 } \ 68 break; \ 69 default: __v = __bug_unaligned_x(__p); break; \ 70 } \ 71 __v; \ 72 }) |
再看__get_unaligned_4_le:
48 #define __get_unaligned_4_le(__p) \ 49 (__p[0] | __p[1] << 8 | __p[2] << 16 | __p[3] << 24) |
我们看到X86平台很简单,就是指针操作。而arm平台需要用字节移位相与的方式。
理由很简单,ARM是要求对齐的,跟它的体系结构有关。想得到正确数据用memcpy或者用字节移位相与的方法。我想我们在编程的时候用指针读取数据的时候满多的,如果不注意有时就可能出现莫名其妙的现象。
总之,当你把代码移植到不同平台时对于这一点需要额外注意。
翻看了以前的日记,看到在ADS1.2中试验结果:
char data[10]= {1,2,3,4,5,6,7,8,9,0}; unsigned int d[4]; d[0] = *(unsigned int *)&data[0]; d[1] = *(unsigned int *)&data[1]; d[2] = *(unsigned int *)&data[2]; d[3] = *(unsigned int *)&data[3]; printf("d[0] is 0x%08x\n", d[0]); printf("d[1] is 0x%08x\n", d[1]); printf("d[2] is 0x%08x\n", d[2]); printf("d[3] is 0x%08x\n", d[3]); 结果如下: d[0] is 0x04030201 d[1] is 0x01040302 d[2] is 0x02010403 d[3] is 0x03020104 |