大端存储和小端存储小端每一个字节内需要颠倒吗?

博客访问: 98038
博文数量: 25
博客积分: 548
博客等级: 中士
技术积分: 229
注册时间:
分类: C/C++ 21:02:10
端模式(Endian)的这个词出自Jonathan Swift书写的《格列佛游记》。这本书根据将鸡蛋敲开的方法不同将所有的人分为两类,从圆头开始将鸡蛋敲开的人被归为Big Endian,从尖头开始将鸡蛋敲开的人被归为Littile Endian。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开。在计算机业Big Endian和Little Endian也几乎引起一场战争。在计算机业界,Endian表示数据在存储器中的存放顺序。下文举例说明在计算机中大小端模式的区别。
如果将一个32位的整数0x存放到一个整型变量(int)中,这个整型变量采用大端或者小端模式在内存中的存储由下表所示。为简单起见,本书使用OP0表示一个32位数据的最高字节MSB(Most Significant Byte),使用OP3表示一个32位数据最低字节LSB(Least Significant Byte)。
如果将一个16位的整数0x1234存放到一个短整型变量(short)中。这个短整型变量在内存中的存储在大小端模式由下表所示。
由上表所知,采用大小模式对数据进行存放的主要区别在于在存放的字节顺序,大端方式将高位存放在低地址,小端方式将高位存放在高地址。采用大端方式进行数据存放符合人类的正常思维,而采用小端方式进行数据存放利于计算机处理。到目前为止,采用大端或者小端进行数据存放,其孰优孰劣也没有定论。
有的处理器系统采用了小端方式进行数据存放,如Intel的奔腾。有的处理器系统采用了大端方式进行数据存放,如IBM半导体和Freescale的PowerPC处理器。不仅对于处理器,一些外设的设计中也存在着使用大端或者小端进行数据存放的选择。
因此在一个处理器系统中,有可能存在大端和小端模式同时存在的现象。这一现象为系统的软硬件设计带来了不小的麻烦,这要求系统设计工程师,必须深入理解大端和小端模式的差别。大端与小端模式的差别体现在一个处理器的寄存器,指令集,系统总线等各个层次中。
编写一段程序判断系统中的CPU 是Little endian 还是Big endian 模式?分析:作 为一个计算机相关专业的人,我们应该在计算机组成中都学习过什么叫Little endian 和Big endian。Little endian 和Big endian 是CPU 存放数据的两种不同顺序。对于整型、长整型等数据类型,Big endian 认为第一个字节是最高位字节(按照从低地址到高地址的顺序存放数据的高位字节到低位字节);而Little endian 则相反,它认为第一个字节是最低位字节(按照从低地址到高地址的顺序存放数据的低位字节到高位字节)。例如,假设从内存地址0x0000 开始有以下数据:<FONT style="BACKGROUND-COLOR: rgb(255,255,255)" color=#cc 0x34 0xab 0xcd如 果我们去读取一个地址为0x0000 的四个字节变量,若字节序为big-endian,则读出结果为0x1234abcd;若字节序位little-endian,则读出结果为 0xcdab3412。如果我们将0x1234abcd 写入到以0x0000 开始的内存中,则Little endian 和Big endian 模式的存放结果如下:地址&&&&&&&&&&&&&& 0x1 0x3big-endian&&&&&&&& 0x12&& 0x34&& 0xab&& 0xcdlittle-endian&&&&& 0xcd&& 0xab 0x34&& 0x12一般来说,x86 系列CPU 都是little-endian 的字节序,PowerPC 通常是Big endian,还有的CPU 能通过跳线来设置CPU 工作于Little endian 还是Big endian 模式。解答:显然,解答这个问题的方法只能是将一个字节(CHAR/BYTE 类型)的数据和一个整型数据存放于同样的内存开始地址,通过读取整型数据,分析CHAR/BYTE 数据在整型数据的高位还是低位来判断CPU 工作于Littleendian 还是Big endian 模式。得出如下的答案:
typedef unsigned char BYTE;
int main(int argc, char* argv[])
&&&unsigned int num,*p;
&&&p = &num;
&&&num = 0;
&&&*(BYTE *)p = 0xff;
&&&if(num == 0xff)
&&&&&&printf("little\n");
&&&else //num == 0xff000000
&&&&&&printf("big\n");
&&&return 0;
除了上述方法(通过指针类型强制转换并对整型数据首字节赋值,判断该赋值赋给了高位还是低位)外,还有没有更好的办法呢?我们知道,union 的成员本身就被存放在相同的内存空间(共享内存,正是union 发挥作用、做贡献的去处),因此,我们可以将一个CHAR/BYTE 数据和一个整型数据同时作为一个union 的成员,得出如下答案:
int checkCPU()
&&&union w
&&&&&&int a;
&&&&&&char b;
&&&c.a = 1;
&&&return (c.b == 1);
实现同样的功能,我们来看看Linux 操作系统中相关的源代码是怎么做的:static union { char c[4];
} endian_test = {{ 'l', '?', '?', 'b' } };#define ENDIANNESS ((char)endian_test.mylong)Linux 的内核作者们仅仅用一个union 变量和一个简单的宏定义就实现了一大段代码同样的功能!由以上一段代码我们可以深刻领会到Linux 源代码的精妙之处!(如果ENDIANNESS=’l’表示系统为little endian,为’b’表示big endian )
阅读(14879) | 评论(1) | 转发(1) |
给主人留下些什么吧!~~
如果是64位机器static&un&#105;on&{&&char&c[8];&&unsigned&long&}&endian_test&=&{{'l',0,0,0,0,0,0,'b'}};
请登录后评论。字节序:大端法和小端法 - Broglie - 博客园
什么是大端法和小端法?
在几乎所有的机器上,多字节对象都被存储为连续的字节序列,对象的地址为所使用字节中的最小地址。
例如,假设一个类型为int的变量x的地址为0x100,即&x的值为0x100。那么x的4个字节将被存储在
存储器的0x100,0x101,0x102和0x103的位置。
字节序即为多字节对象存储在内存中的字节顺序,有两种不同的存储方案:大端法和小端法。现代的处理器大多为双端法,大小端都支持,可以配置称大端法或者小端法。
最高有效字节在最前面的方式称为大端法,例如假设变量x类型为int型,位于地址0x100的地方,其16进制值为0x,地址范围为0x100到0x103字节。
对于大端法的机器来说:
由上图可见,地址从左向右增长,x的最高有效字节12在最前面存储。这正好和我们平时书写习惯一致,先书写最高有效字节,再依次写其余字节。
最低有效字节在最前面的方式成为小端法,这正好和大端法相反,仍然用大端法中举的例子说明:
由上图可见,地址依然从左向右增长,x的最低有效字节在最前面存储,与大端法相反。
如何判断我的机器是大端法还是小端法?
在《UNIX网络编程》上有一个程序可以判断一个机器是大端法还是小端法,我稍加改造了一下:
#include&stdio.h&
#include&stdlib.h&
main(int argc, char **argv)
c[sizeof(short)];
un.s = 0x0102;
if (sizeof(short) == 2) {
if (un.c[0] == 1 && un.c[1] == 2)
printf(&大端法\n&);
else if (un.c[0] == 2 && un.c[1] == 1)
printf(&小端法\n&);
printf(&不能判断\n&);
printf(&sizeof(short) = %d\n&, sizeof(short));
大端法和小端法对程序员有什么影响?
多数程序员不必关系所使用的机器是大端法还是小端法,在大多数情况下都不会出问题,但在某些特殊情况下这有可能成为问题:
1.编写网络程序时,主机之间通过网络相互通信,不同主机之间可能采用不同的方法,而且网络字节序和主机字节序也可能不同。
当小端法机器产生的数据被发送到大端法机器或者反方向发送时会发现接受程序子里面的字节成了反序的。为了避免这种情况的发
生,规定网络应用程序在将数据发送之前现将数据转换称网络字节序,在接收主机那边,主机再将网络字节序的数据转换成适合本
主机的主机字节序,从而避免了字节序异常。(网络字节序为大端法)
网络编程中常用的转换函数有如下几个:
uing16_t htons(uint16_t host16bitvalue);
// 参数为16位主机字节序的值,返回值是16位网络字节序的值
uint32_t htonl(uint32_t host32bitvalue);
// 参数为32位主机字节序的值,返回值是32位网络字节序的值
uint16_t ntohs(uint16_t net16bitvalue);
// 参数为16位网络字节序的值,返回值是16位主机字节序的值
uint32_t ntohl(uint32_t net32bitvalue);
// 参数为16位网络字节序的值,返回值是16位主机字节序的值
2.当调试程序时常常需要将程序编译成汇编形式,当阅读汇编代码时数据的字节序很重要,需要根据自己的机器是大端法还是小
端法来不同对待,以免搞错字节顺序。
3.当编写规避正常类型系统的程序时,在C语言中可以使用强制类型转换来允许以一中类型引用一个对象,而这种数据类型与创建
这个对象时定义的数据类型不同,大多数应用编程都不推荐这种编码技巧,但是它们对于系统级编程来说十分有用。
参考资料:
《深入理解计算机系统》2nd
《UNIX网络编程 卷一》3th没有更多推荐了,
不良信息举报
举报内容:
大端模式、小端模式和网络字节顺序【转】
举报原因:
原文地址:
原因补充:
最多只允许输入30个字
加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!大端模式和小端模式 - 西窗伏龙 - 博客园
大端格式:
小端格式:
&请写一个C函数,若处理器是Big_endian的,则返回0;若是Little_endian的,则返回1
int checkCPU( )
嵌入式系统开发者应该对和模式非常了解。例如,宽的数在模式内存中的存放方式(假设从地址开始存放)为:
而在模式内存中的存放方式则为:
32bit宽的数0x在Little-endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:
而在Big-endian模式CPU内存中的存放方式则为:
联合体union的存放顺序是所有成员都从低地址开始存放。
=============== 呵呵 还是附上 另一段代码吧,摘自一个开源项目 ====
int& big_endian (void)
& & && union{&&&&& & && & &&&&& char c[sizeof(long)];&&&&&& }u;
&&&&&&& u.l = 1;&&&&&& return& (u.c[sizeof(long) - 1] == 1);&&&& }
有时候,用C语言写程序时需要知道是大端模式还是小端模式。 所谓的大端模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;所谓的小端模式,是指数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中。为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如果将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。例如一个16bit的short型x,在内存中的地址为0x0010,x的值为0x1122,那么0x11为高字节,0x22为低字节。对于大端模式,就将0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。小端模式,刚好相反。我们常用的X86结构是小端模式,而KEIL C51则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。
下面这段代码可以用来测试一下你的编译器是大端模式还是小端模式:
char x0,x1;x=0x1122;x0=((char*)&x)[0];& //低地址单元x1=((char*)&x)[1];& //高地址单元若x0=0x11,则是大端; 若x0=0x22,则是小端......数据表示&大端法&&小端法
UNXI网络编程》定义:术语“小端”和“大端”表示多字节值的哪一端(小端或大端)存储在该值的起始地址。小端存在起始地址,即是小端字节序;大端存在起始地址,即是大端字节序。
也可以说:
1.小端法(Little-Endian)就是低位字节排放在内存的低地址端即该值的起始地址,高位字节排放在内存的高地址端。
2.大端法(Big-Endian)就是高位字节排放在内存的低地址端即该值的起始地址,低位字节排放在内存的高地址端。
举个简单的例子,对于整形0x。它在大端法和小端法的系统内中,分别如图1所示的方式存放。
网络字节序
我们知道网络上的数据流是字节流,对于一个多字节数值,在进行网络传输的时候,先传递哪个字节?也就是说,当接收端收到第一个字节的时候,它是将这个字节作为高位还是低位来处理呢?
网络字节序定义:收到的第一个字节被当作高位看待,这就要求发送端发送的第一个字节应当是高位。而在发送端发送数据时,发送的第一个字节是该数字在内存中起始地址对应的字节。可见多字节数值在发送前,在内存中数值应该以大端法存放。
网络字节序说是大端字节序。
比如我们经过网络发送0x这个整形,在80X86平台中,它是以小端法存放的,在发送前需要使用系统提供的htonl将其转换成大端法存放,如图2所示。
字节序测试程序
不同cpu平台上字节序通常也不一样,下面写个简单的C程序,它可以测试不同平台上的字节序。
#include&&stdio.h&
#include&&netinet/in.h&
int&main()
int&i_num&=&0x;
printf("[0]:0x%x\n",&*((char&*)&i_num&+&0));
printf("[1]:0x%x\n",&*((char&*)&i_num&+&1));
printf("[2]:0x%x\n",&*((char&*)&i_num&+&2));
printf("[3]:0x%x\n",&*((char&*)&i_num&+&3));
i_num&=&htonl(i_num);
printf("[0]:0x%x\n",&*((char&*)&i_num&+&0));
printf("[1]:0x%x\n",&*((char&*)&i_num&+&1));
printf("[2]:0x%x\n",&*((char&*)&i_num&+&2));
printf("[3]:0x%x\n",&*((char&*)&i_num&+&3));
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

我要回帖

更多关于 什么是大端小端字节序 的文章

 

随机推荐