CPU是Little endian还是Big endian模式
时间:2010-07-06 来源:静止的流水
Little endian和Big endian是CPU存放数据的两种不同顺序。对于整型、长整型等数据类型,Big endian认为第一个字节是最高位字节(按照从低地址到高地址的顺序存放数据的高位字节到低位字节);而Little endian则相反,它认为第一个字节是最低位字节(按照从低地址到高地址的顺序存放数据的低位字节到高位字节)。
Big: 从内存地址的低到高位保存数据的从高到底位
Little:从内存地址的低到高位保存数据的从低到高位
内存内容如下:
0x0000 |
0x0001 |
0x0002 |
0x0003 |
0x12 |
0x23 |
0xab |
0xcd |
如果是big:读出来的内容是0x1234abcd,如果是little读出来的内容是0xcdab3412
把0x1234abcd写入:
内存地质 |
0x0000 |
0x0001 |
0x0002 |
0x0003 |
Big |
0x12 |
0x23 |
0xab |
0xcd |
Little |
0xcd |
0xab |
0x34 |
0x12 |
一般来说,x86系列CPU都是little-endian的字节序,PowerPC通常是Big endian,还有的CPU能通过跳线来设置CPU工作于Little endian还是Big endian模式。
解答这个问题的方法只能是将一个字节(CHAR/BYTE类型)的数据和一个整型数据存放于同样的内存开始地址,通过读取整型数据,分析CHAR/BYTE数据在整型数据的高位还是低位来判断CPU工作于Little endian还是Big endian模式。得出如下的答案:
typedef unsigned char BYTE;
int main(int argc, char* argv[])
{
unsigned int num,*p;
p = #
num = 0;
*(BYTE *)p = 0xff;
if(num == 0xff)
{
printf("The endian of cpu is little\n");
}
else //num == 0xff000000
{
printf("The endian of cpu is big\n");
}
return 0;
}
除了上述方法(通过指针类型强制转换并对整型数据首字节赋值,判断该赋值赋给了高位还是低位)外,还有没有更好的办法呢?我们知道,union的成员本身就被存放在相同的内存空间(共享内存,正是union发挥作用、做贡献的去处),因此,我们可以将一个CHAR/BYTE数据和一个整型数据同时作为一个union的成员,得出如下答案:
int checkCPU()
{
{
union w
{
int a;
char b;
} c;
c.a = 1;
return (c.b == 1);
}
}
实现同样的功能,我们来看看Linux操作系统中相关的源代码是怎么做的:
static union { char c[4]; unsigned long l; } endian_test = { { 'l', '?', '?', 'b' } };
#define ENDIANNESS ((char)endian_test.l)
Linux的内核作者们仅仅用一个union变量和一个简单的宏定义就实现了一大段代码同样的功能!由以上一段代码我们可以深刻领会到Linux源代码的精妙之处!