Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1642412
  • 博文数量: 268
  • 博客积分: 8708
  • 博客等级: 中将
  • 技术积分: 3764
  • 用 户 组: 普通用户
  • 注册时间: 2007-04-06 15:58
文章分类

全部博文(268)

文章存档

2014年(1)

2013年(15)

2012年(23)

2011年(60)

2010年(51)

2009年(12)

2008年(59)

2007年(47)

分类: BSD

2010-11-13 00:19:15

存储单元在计算机中最小的信息单位是bit,也就是一个二进制位,8个bit组成一个Byte,也就是字节。一个存储单元可以存储一个字节,也就是8个二进制位。计算机的存储器容量是以字节为最小单位来计算的,对于一个有128个存储单元的存储器,可以说它的容量为128字节。如果有一个1KB的存储器则它有1024个存储单元,它的编号为从0-1023。
计算机最小的单位是位(bit),每8位组成一个字节(Byte),字节(B)也是存储器的最小存储单元。
b、B、Kb、KB、Mb、MB、Gb、GB之间的单位换算如下:
1B = 2的3次方*b = 8b
1Kb = 2的10次方*b = 1024b
1KB = 2的13次方*b = 2的10次方*B =1024B
1Mb = 2的20次方*b 1MB = 2的23次方*b = 2的20次方*B
1Gb = 2的30次方*b 1GB = 2的33次方*b = 2的30次方*B
4Gb = 2的32次方*b 4GB = 2的35次方*b = 2的32次方*B
 
字节序,又称端序,尾序,英文:Endianness。在计算机科学领域中,字节序是指存放多字节数据的字节(byte)的顺序,典型的情况是整数在内存中的存放方式和网络传输的传输顺序。Endianness有时候也可以用指位序(bit)。一般而言,字节序指示了一个UCS-2字符的哪个字节存储在低地址。如果LSByte在MSByte的前面,即LSB为低地址,则该字节序是小端序;反之则是大端序。在网络编程中,字节序是一个必须被考虑的因素,因为不同的处理器体系可能采用不同的字节序。在多平台的代码编程中,字节序可能会导致难以察觉的bug。基本的字节序

对于单一的字节(a byte),大部分以相同的顺序处理(bit),因此单字节的存放方法和传输方式一般相同。

对于多字节数据,如整数(32位机中一般占4字节),在不同的处理器的存放方式主要有两种,以内存中0x0A0B0C0D的存放方式为例,分别有以下几种方式:

注: 0x前缀代表十六进制。 [] 大端序

大端序(英:big-endian)或稱大尾序

Big-Endian.svg
  • 数据以8bit为单位:
地址增长方向  →
... 0x0A 0x0B 0x0C 0x0D ...

示例中,(MSB, Most Significant Byte)是0x0A 存储在最低的内存地址处。下一个字节0x0B存在后面的地址处。正类似于十六进制字节从左到右的阅读顺序。

  • 数据以16bit为单位:
地址增长方向  →
... 0x0A0B 0x0C0D ...

最高的16bit单元0x0A0B存储在低位。

[] 小端序

小端序(英:little-endian)或稱小尾序

Little-Endian.svg
  • 数据以8bit为单位:
地址增长方向  →
... 0x0D 0x0C 0x0B 0x0A ...

(LSB,Least Significant Byte)是0x0D 存储在最低的内存地址处。后面字节依次存在后面的地址处。

  • 数据以16bit为单位:
地址增长方向  →
... 0x0C0D 0x0A0B ...

最低的16bit单元0x0C0D存储在低位。

  • 更改地址的增长方向:

当更改地址的增长方向,使之由右至左时,表格更具有可阅读性。

←  地址增长方向
... 0x0A 0x0B 0x0C 0x0D ...

最低有效位(LSB)是0x0D 存储在最低的内存地址处。后面字节依次存在后面的地址处。

←  地址增长方向
... 0x0A0B 0x0C0D ...

最低的16bit单元0x0C0D存储在低位。

[] 混合序

混合序(英:middle-endian)具有更复杂的顺序。以为例,0x0A0B0C0D被存储为:

  • 32bit在PDP-11的存储方式
地址增长方向  →
... 0x0B 0x0A 0x0D 0x0C ...

可以看作最高的16bit位和低位以大端序存储,但16bit内部以小端存储。


[] 处理器体系
  • ,,,,等处理器为Little endian。
  • ,,,,(除V9外)等处理器为Big endian
  • , (除PowerPC 970外), , , , and 的字节序是可配置的。


[] 网络序

网络传输一般采用大端序,也被称之为网络字节序,或网络序。协议中定义大端序为网络字节序。

socket API定义了一组转换函数,用于16和32bit整数在网络序和本机字节序之间的转换。htonl,htons用于本机序转换到网络序;ntohl,ntohs用于网络序转换到本机序。

[] 位序

一般用于描述串行设备的传输顺序。一般硬件传输采用小端序(先传低位),但协议采用大端序。中只有的底端会涉及到。

基本的字节序

对于单一的字节(a byte),大部分以相同的顺序处理(bit),因此单字节的存放方法和传输方式一般相同。

对于多字节数据,如整数(32位机中一般占4字节),在不同的处理器的存放方式主要有两种,以内存中0x0A0B0C0D的存放方式为例,分别有以下几种方式:

注: 0x前缀代表十六进制。 [] 大端序

大端序(英:big-endian)或稱大尾序

Big-Endian.svg
  • 数据以8bit为单位:
地址增长方向  →
... 0x0A 0x0B 0x0C 0x0D ...

示例中,(MSB, Most Significant Byte)是0x0A 存储在最低的内存地址处。下一个字节0x0B存在后面的地址处。正类似于十六进制字节从左到右的阅读顺序。

  • 数据以16bit为单位:
地址增长方向  →
... 0x0A0B 0x0C0D ...

最高的16bit单元0x0A0B存储在低位。

[] 小端序

小端序(英:little-endian)或稱小尾序

Little-Endian.svg
  • 数据以8bit为单位:
地址增长方向  →
... 0x0D 0x0C 0x0B 0x0A ...

(LSB,Least Significant Byte)是0x0D 存储在最低的内存地址处。后面字节依次存在后面的地址处。

  • 数据以16bit为单位:
地址增长方向  →
... 0x0C0D 0x0A0B ...

最低的16bit单元0x0C0D存储在低位。

  • 更改地址的增长方向:

当更改地址的增长方向,使之由右至左时,表格更具有可阅读性。

←  地址增长方向
... 0x0A 0x0B 0x0C 0x0D ...

最低有效位(LSB)是0x0D 存储在最低的内存地址处。后面字节依次存在后面的地址处。

←  地址增长方向
... 0x0A0B 0x0C0D ...

最低的16bit单元0x0C0D存储在低位。

[] 混合序

混合序(英:middle-endian)具有更复杂的顺序。以为例,0x0A0B0C0D被存储为:

  • 32bit在PDP-11的存储方式
地址增长方向  →
... 0x0B 0x0A 0x0D 0x0C ...

可以看作最高的16bit位和低位以大端序存储,但16bit内部以小端存储。


[] 处理器体系
  • ,,,,等处理器为Little endian。
  • ,,,,(除V9外)等处理器为Big endian
  • , (除PowerPC 970外), , , , and 的字节序是可配置的。


[] 网络序

网络传输一般采用大端序,也被称之为网络字节序,或网络序。协议中定义大端序为网络字节序。

socket API定义了一组转换函数,用于16和32bit整数在网络序和本机字节序之间的转换。htonl,htons用于本机序转换到网络序;ntohl,ntohs用于网络序转换到本机序。

[] 位序

一般用于描述串行设备的传输顺序。一般硬件传输采用小端序(先传低位),但协议采用大端序。中只有的底端会涉及到。


一、什么是大小端问题

(FromComputer Systems,A Programer's Perspective)在几乎所有的机器上,多字节对象被存储为连续的字节序列,对象的地址为所使用字节序列中最低字节地址。

小端:某些机器选择在存储器中按照从最低有效字节到最高有效字节的顺序存储对象,这种最低有效字节在最前面的表示方式被称为小端法(little endian) 这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;

       大端:某些机器则按照从最高有效字节到最低有效字节的顺序储存,这种最高有效字节在最前面的方式被称为大端法(big endian) 这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致。

 

 举个例子来说名大小端 比如一个int x, 地址为0x100, 它的值为0x1234567. 则它所占据的0x100, 0x101, 0x102, 0x103地址组织如下图:Big Endian and Little Endian[转载]

 二、为什么会有大小端模式之分呢?

这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为 8bit。但是在C语言中除了8bitchar之外,还有16bitshort型,32bitlong型(要看具体的编译器),另外,对于位数大于 8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如果将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。例如一个16bitshortx,在内存中的地址为0x0010x的值为0x1122,那么0x11为高字节,0x22为低字节。对于 大端模式,就将0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。小端模式,刚好相反。我们常用的X86结构是小端模 式,而KEIL C51则为大端模式。很多的ARMDSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。

 

三、如何区分大小端问题:

方法1

#include

 

int main(void)

{

       int i = 1;

       unsigned char *pointer;

 

       pointer = (unsigned char *)&i;

       if(*pointer)

       {

              printf("litttle_endian");

       }

       else

       {

              printf("big endian\n");

       }

 

       return 0;

}

       C中的数据类型都是从内存的低地址向高地址扩展,取址运算"&"都是取低地址。小端方式中(i占至少两个字节的长度)则i所分配的内存最小地址那个字节中就存着1,其他字节是0大端的话则1i的最高地址字节处存放,char是一个字节,所以强制将char型量p指向ip指向的一定是i的最低地址,那么就可以判断p中的值是不是1来确定是不是小端。

 

方法2

#include

 

int main(void)

{

       union {

              short a;

              char ch;

       } u;

       u.a = 1;

 

       if (u.ch == 1)

       {

              printf("Littel endian\n");

       }

       else

       {

              printf("Big endian\n");

       }

}

       利用联合体的特点,数据成员共享内存空间,union中元素的起始地址都是相同的——位于联合的开始。 char来截取感兴趣的字节

 

四、需要考虑大小端(字节顺序)的情况

1、所写的程序需要向不同的硬件平台迁移,说不定哪一个平台是大端还是小端,为了保证可移植性,一定提前考虑好。

2. 在不同类型的机器之间通过网络传送二进制数据时。 一个常见的问题是当小端法机器产生的数据被发送到大端法机器或者反之时,接受程序会发现,字(word)里的字节(byte)成了反序的。为了避免这类问 题,网络应用程序的代码编写必须遵守已建立的关于字节顺序的规则,以确保发送方机器将它的内部表示转换成网络标准,而接受方机器则将网络标准转换为它的内部标准。

3. 当阅读表示整数的字节序列时。这通常发生在检查机器级程序时,e.g.:反汇编得到的一条指令:
80483bd: 01 05 64 94 04 08        add �x, 0x8049464

3. 当编写强转的类型系统的程序时。如写入的数据为u32型,但是读取的时候却是char型的。如:0x1234, 大端读取为12时,小端独到的是34

六、提高程序的可移植性

使用宏编译

#ifdef LITTLE_ENDIAN

//小端的代码

#else

//大端的代码

#endif

 

七、大、小端之间的转换

1、小端转换为大端

#include

 

void show_byte(char *addr, int len)

{

       int i;

 

       for (i = 0; i < len; i++)

       {

              printf("%.2x \t", addr[i]);

       }

       printf("\n");

}

 

int endian_convert(int t)

{

       int result;

       int i;

 

       result = 0;

       for (i = 0; i < sizeof(t); i++)

       {

              result <<= 8;

              result |= (t & 0xFF);

              t >>= 8;

       }

 

       return result;

}

 

int main(void)

{

       int i;

       int ret;

 

       i = 0x1234567;

 

       show_byte((char *)&i, sizeof(int));

       ret = endian_convert(i);

       show_byte((char *)&ret, sizeof(int));

 

       return 0;

}

阅读(2135) | 评论(0) | 转发(0) |
0

上一篇:VC编译选项

下一篇:exec函数族

给主人留下些什么吧!~~