本帖最后由 wljyy521 于 2012-5-30 23:22 编辑

目前在各种体系的计算机中通常采用的字节存储机制主要有两种:Big-EndianLittle-Endian,下面先 从字节序说起。
字节序:就是字节的顺序,就是多于一个字节的数据在内存中的存储顺序。
a)Little-Endian:就是数据的低位字节放在内存的低地址端,高位字节放在内存的高地址端
b)Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端
c) 网络字节序:TCP/IP隔层协议将字节序定义为Big-Endian,因此TCP/IP协议中使用的字节序通常称之为网络字 节序
1.1   什么是高/低地址端
      我们在C程序映像中内存的空间布局情况:大致是这样的
----------------------- 最高内存地址 0xffffffff
栈底

栈顶

-----------------------
NULL (空洞)
-----------------------

-----------------------
未初始 化的数据
----------------------- 统称数据段
初始化的数据
-----------------------
正 文段(代码段)
----------------------- 最低内存地址 0x00000000

以上图为例如果我们在栈 上分配一个unsigned char buf[4],那么这个数组变量在栈上是如何布局的呢?看下图:
栈底 (高地址)
----------
buf[3]
buf[2]
buf[1]
buf[0]
----------
栈顶 (低地址)
1.2 什么是高/低字节
  那么什么是高/低字节呢?假设我们有一个32位无符号说0x12345678,那么高位和地位各是什么呢?在我们平时见到的数字几乎都是十进制的,在十进制中我们可以很清楚的知道,左边的是高位,右边的是低位,其实其他进制也是这样,就拿0x12345678来说:从高位到低位依次是:0x12,0x34,0x56,0x78.
高/低地址端和高/低字节都弄清了。我们再来回顾 一下Big-Endian和Little-Endian的定义,并用图示说明两种字节序:
以unsigned int value = 0x12345678为例,分别看看在两种字节序下其存储情况,我们可以用unsigned char buf[4]来表示value:
如下图:  
Big-Endian: 低地址存放高位,如下图:
栈底 (高地址)
---------------
buf[3] (0x78) -- 低位
buf[2] (0x56)
buf[1] (0x34)
buf[0] (0x12) -- 高位
---------------
栈顶 (低地址)
Little-Endian: 低地址存放低位,如下图:
栈底 (高地址)
---------------
buf[3] (0x12) -- 高位
buf[2] (0x34)
buf[1] (0x56)
buf[0] (0x78) -- 低位
--------------
栈 顶 (低地址)

这样就该明白了大端和小端的意思了吧。
2.Big-EndianLittle-Endian优缺点
Big-Endian优点:靠首先提取高位字节,你总是可以由看看在偏移位置为0的字节来确定这个数字是 正数还是负数。你不必知道这个数值有多长,或者你也不必过一些字节来看这个数值是否含有符号位这个数值是以它们被打印出来的顺序存放的,所以从二进制到十进制的函数特别有效。因而,对于不同要求的机器,在设计存取方式时就会不同。
Little-Endian优点:提取一个,两个,四个或者更长字节数据的汇编指令以与其他所有格式相同的方式进行:首先在偏移地址为0的地方提取最低位的字节,因为地址偏移和字节数是一对 一的关系,多重精度的数学函数就相对地容易写了如果你增加数字的值,你可能在左边增加数字(高位非指数函数需要更多的数字)。因此, 经常需要增加两位数字并移动存储器里所有Big-endian顺序的数字,把所有数向右移,这会增加计算机的工作量。不过,使用Little- Endian的存储器中不重要的字节可以存在它原来的位置,新的数可以存在它的右边的高位地址里。这就意味着计算机中的某些计算可以变得更加简单和快速。

3.那么怎么判断一个CPU是大端模式还是小端模式呢?
由于联合体union的存放顺序是所有成员都从低地址开始存放,利用该特性就可以轻松地获得了CPU对内存采用Little- endian还是Big-endian模式读写。例如:
int checkCPUendian(){
union {
unsigned int a;
unsigned char b;            
}c;
c.a = 1;
return (c.b == 1);      
}   /*return 1 : little-endian, return 0:big-endian*/
在Linux内核源代码中是怎么判断大端和小端的呢?
在Linux中是使用联合体和宏定义判断的:
static union
{
char c[4];
unsigned long l;
}endian_test = { { 'l','?','?','b' } };
#define ENDIANNESS ((char)endian_test.l)
如果 ENDIANNESS ==‘l’就是小端模式
如果 ENDIANNESS ==‘b’就是大端模式






共收到 6 条回复
f8915345 · #2 · 2012-5-31 23:23:12  回复 支持 反对
学习了!谢谢分享
Castelo · #3 · 2012-6-17 13:56:41  回复 支持 反对
用联合体判断大端小端。确实很巧妙

点评

是的啊,这是运用联合体在内存中的特点  详情 回复 发表于 2012-6-17 20:39
wljyy521 · #4 · 2012-6-17 20:39:53  回复 支持 反对
Castelo 发表于 2012-6-17 13:56
用联合体判断大端小端。确实很巧妙

是的啊,这是运用联合体在内存中的特点

点评

你是超级版主,我就不好意思加分了。。。。。很聪明的点子  详情 回复 发表于 2012-6-17 20:48
Castelo · #5 · 2012-6-17 20:48:17  回复 支持 反对
wljyy521 发表于 2012-6-17 20:39
是的啊,这是运用联合体在内存中的特点

你是超级版主,我就不好意思加分了。。。。。很聪明的点子
callmesb · #6 · 2012-6-17 21:36:14  回复 支持 反对
学习 了
suogongy · #7 · 2012-6-17 22:28:39  回复 支持 反对
对这个,一直迷迷糊糊的
回帖
B Color Image Link Quote Code Smilies
Command + Enter
快速回复 返回顶部 返回列表