转:http://blog.csdn.net/usownh/article/details/42614185

大端模式和小端模式是计算机中经常涉及到的两种字节序,也有大端对齐、小端对齐、大尾、小尾等叫法。

一、起源

说起这两种模式,就不得不提一下大端(Big-endian)和小端(Little-endian)这两个英文上的起源。

“endian”一词来源于乔纳森·斯威夫特的小说格列佛游记。Lilliput和Blefuscu这两个强国在过去的36个月中一直在苦战。战争的原因:大家都知道,吃鸡蛋的时候,原始的方法是打破鸡蛋较大的一端(Big-End),可以那时的皇帝的祖父由于小时侯吃鸡蛋,按这种方法把手指弄破了,因此他的父亲,就下令,命令所有的子民吃鸡蛋的时候,必须先打破鸡蛋较小的一端(Little-End),违令者重罚。然后老百姓对此法令极为反感,期间发生了多次叛乱,其中一个皇帝因此送命,另一个丢了王位,产生叛乱的原因就是另一个国家Blefuscu的国王大臣煽动起来的,叛乱平息后,就逃到这个帝国避难。据估计,先后几次有11000余人情愿死也不肯去打破鸡蛋较小的端吃鸡蛋。这个其实讽刺当时英国和法国之间持续的冲突。(引自http://blog.csdn.net/ce123_zhouwei/article/details/6971544)其中两种方法吃鸡蛋的人分别被称为Big-endians和Little-endians。1980年,Danny Cohen在其著名的论文”On Holy Wars and a Plea for Peace”中,为平息一场关于字节该以什么样的顺序传送的争论,而引用了该词。

二、存储模式

接下来就说说为什么会有字节序的问题。

计算机在存储数据的时候,是以字节(byte)为基本单位来存储的,因此存储单字节类型的数据(比如char)不存在字节序的问题。但存储多字节的数据的时候(比方说4字节的int变量),就涉及到了以一个什么样的顺序来存储。下面举例来说明大端和小端的存储方式。

定义变量 unsigned long long a=0x1122334455667788

变量a是一个64位的无符号整数,共需要8个字节来存储,那么在两种模式下是如何存储的呢?

||--1--||--2--||--3--||--4--||--5--||--6--||--7--||--8--||  地址

||  11 ||  22 ||  33 ||  44 ||  55 ||  66 ||  77 ||  88 ||  大端模式

||  88 ||  77 ||  66 ||  55 ||  44 ||  33 ||  22 ||  11 ||  小端模式

从中很容易可以看出各自的存储特点。

三、需要注意的几个问题

1.大端模式和小端模式是以基本类型为单位的

对于long long a 和 struct{ char a;short b;int c;}二者同样占据了8个字节的空间,在存储上,前者上面已经介绍,后者则是先存储一个char,空一个字节,然后按照大端/小端模式存储short,最后按照大端/小端模式存储int。

2.大端模式与小端模式的实际应用范围

在我们日常使用的x86架构的计算机中(其他类别的可能会采用大端模式或可配置模式,可以通过查阅资料或者用下文的代码进行测试),都是使用的小端模式,而网络字节序是大端模式的。这就使得在网络通信时进行字节序的转换变得极为重要。比方说,通信双方规定了了通信头为一个4字节的魔数(Magic Number),而一方按着大端序的模式发送,一方按着小端序的模式解读,那么两方的通信就会失败。如果没有这个魔数,而在内部的数据中出现这样的问题则会更加的麻烦。

3.文件存储中的模式

文件的存储一般都是以字节来进行操作的,因此,在文件中以什么样的字节序需要程序的编写者加以注意。比方说下面的程序:

  1. int a=0x11223344;
  2. FILE *fp;
  3. fp=fopen("test","wb");
  4. fwrite(&a,sizeof(a),1,fp);
  5. fclose(fp);

用十六进制编辑器打开文件之后,我们会发现文件的内容是44332211。原因很简单,fwrite函数直接把内存中的内容按顺序写入了文件,因此内存中是小端模式存储的,所以写入文件也是小端模式。

四、优缺点

大端模式,由于符号位和数值的高位存在地址的低位,会优先被读到,更容易先确定数据的重要信息。

小端模式,在进行类型转换的时候不需要调整数据。如int强制转换到char,计算机不需要做任何调整,直接读取int的第一个字节即可。

五、大端和小端的检测

对于大端模式和小端模式的检测,可以利用上面所说的强制类型转换。

  1. bool isLittleEndian()
  2. {
  3. short a=0x0061;
  4. if((char)a=='a') return true;
  5. else return false;
  6. }

在查阅资料后,还发现了另外一个方法,利用到了被我遗忘很久的一个数据结构,联合体union。

  1. bool isLittleEndian()
  2. {
  3. union
  4. {
  5. short a;
  6. char  b;
  7. }test;
  8. test.a=0x0061;
  9. if(test.b=='a') return true;
  10. else return false;
  11. }

这个方法利用了联合体共用内存的特性,因此回避了强制类型转换。

六、Qt中大端小端的转换

Qt中<QtEndian>包含了大端小端转换的几个函数

  1. T   qFromBigEndian(const uchar * src)
  2. T   qFromBigEndian(T src)
  3. T   qFromLittleEndian(const uchar * src)
  4. T   qFromLittleEndian(T src)
  5. void    qToBigEndian(T src, uchar * dest)
  6. T   qToBigEndian(T src)
  7. void    qToLittleEndian(T src, uchar * dest)
  8. T   qToLittleEndian(T src)

下面对这个几个函数进行简单的说明。

  1. union{
  2. int a;
  3. char b[4];
  4. }test1,test2;
  5. test1.a=0x61626364;
  6. test2.a=qFromBigEndian(test1.a);
  7. qDebug()<<test1.b[0]<<test1.b[1]<<test1.b[2]<<test1.b[3];
  8. qDebug()<<test2.b[0]<<test2.b[1]<<test2.b[2]<<test2.b[3];

对于qFromBigEndian()函数,它会判断执行程序的主机的字节序,如果是大端模式的计算机,那么只是读取数据,不进行转换,如果是小端模式的计算机,那么则进行转换。

因此我在本机(小端模式)上的的执行结果是:

d c b a

a b c d

可以看出,它将数据进行了转换。

对于qFromLittleEndian()函数,和前者类似。对于大端模式的计算机进行转换,对于小端模式的计算机只是读取数据。

  1. union{
  2. int a;
  3. char b[4];
  4. }test1,test2;
  5. test1.a=0x61626364;
  6. test2.a=qFromLittleEndian(test1.a);
  7. qToBigEndian(test1.a,(uchar*)test2.b);
  8. qDebug()<<test1.b[0]<<test1.b[1]<<test1.b[2]<<test1.b[3];
  9. qDebug()<<test2.b[0]<<test2.b[1]<<test2.b[2]<<test2.b[3];

对于qToBigEndian()函数,也有着上面的规则,对于小端模式的计算机进行转换,对于大端模式的计算机只进行读取。

因此,本机(小端模式)的执行结果是:

d c b a

a b c d

对于qToLittleEndian()函数,只对大端模式的计算机进行转换。

需要注意的是,Qt中的模板T只针对有符号和无符号的整型,对于浮点型(一般也不会用到),需要进行强制类型转换。

Qt大小端的更多相关文章

  1. ARM CPU大小端

    ARM CPU大小端: 大端模式:低位字节存在高地址上,高位字节存在低地址上 小端模式:高位字节存在高地址上,低位字节存在低地址上 STM32属于小端模式,简单的说,比如u32 temp=0X1234 ...

  2. C语言共用体、大小端、枚举

    1.共用体和结构体的相同和不同 (1)相同点就是操作语法几乎相同.(2)不同点是本质上的不同.struct是多个独立元素(内存空间)打包在一起:union是一个元素(内存空间)的多种不同解析方式. # ...

  3. 联合体union和大小端(big-endian、little-endian)

    1.联合体union的基本特性——和struct的同与不同 union,中文名“联合体.共用体”,在某种程度上类似结构体struct的一种数据结构,共用体(union)和结构体(struct)同样可以 ...

  4. CPU的大小端模式

    不同体系结构的CPU,数据在内存中存放的排列顺序是不一样的. 存储器中对数据的存储是以字节(Byte)为基本单位的,因此,字(Word)和半字(Half-Word)在存储器中就有两种次序,分别称为:大 ...

  5. C++/java之间的Socket通信大小端注意事项

    在一个物联往项目中,需要java云平台与一个客户端做socket定制协议的通信:然而在第一次测试时,并没有按照预想的那样完成解析.查找资料以后是因为客户端的数据读取方式为小端模式,而java默认采用大 ...

  6. 从inet_pton()看大小端字节序

    #include<stdio.h> #include<netinet/in.h> #include<stdlib.h> #include<string.h&g ...

  7. 【转】 CPU大小端

    大端模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中:小端模式,是指数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中. 为什么会有大小端模式之分呢?这是因为 ...

  8. linux kernel 如何处理大小端

    暂时在用MPC8309,不太清楚大小端内核是什么时候给转的. 今天看了关于readl和writel具体实现的文章 今天就主要来分析下readl/writel如何实现高效的数据swap和寄存器读写.我们 ...

  9. 关键词:ACM & 大小端 & 面试官

    关于“ACM” fender0107401 :面试了一个在ACM拿过奖的人 我问了他几个问题: 读取数组中的一个元素,计算复杂度是多少,回答不清楚. 往链表里面存一个数,不排序的情况下,计算复杂度是多 ...

随机推荐

  1. Windows7 x64系统下安装Nodejs并在WebStorm下搭建编译less环境

    1. 打开Nodejs官网http://www.nodejs.org/,点“DOWNLOADS”,点64-bit下载“node-v0.10.33-x64.msi”. 2. 下载好后,双击“node-v ...

  2. ubuntu安装wine的方法

    使用命令行安装: 1.打开终端,使用命令:sudo apt-get install wine 2.它可能会出现选择哪个版本的安装,develop是开发版本,stable是稳定版本. 通常我们选择sta ...

  3. MySQL - 查询今天的数据(以及昨天、本月、上个月、今年...) 查询Datetime 时间的数据

    1,查询当天(今天)的数据 1 SELECT * FROM `order` WHERE TO_DAYS(order_time) = TO_DAYS(NOW()) 2,查询昨天的数据 1 SELECT  ...

  4. .Net站点架构设计(八)測试

    .Net站点架构时间(八)測试 一般而言.总体測试策略是:先针对部分系统进行性能及压力測试,得到各部分的峰值处理性能:再模拟总体流程測试,此时倒不用依照峰值跑,重点測试总体业务流程及业务预期负荷. 在 ...

  5. J.U.C Atomic(一)CAS原理

    CAS概念 CAS:Compare And Swap,比较并交换.java.util.concurrent包完全是建立于CAS机制之上的. CAS原理 Java CAS是通过调用Unsafe的nati ...

  6. jQuery中on()方法用法实例

    这篇文章主要介绍了jQuery中on()方法用法,实例分析了on()方法的功能.定义及在匹配元素上绑定一个或者多个事件处理函数的使用技巧,需要的朋友可以参考下 本文实例讲述了jQuery中on()方法 ...

  7. win10专业版密钥激活

    win10专业版密钥激活 1.查看激活状态,win按键>设置(左下角倒数第二个)>更新和安全>激活---------提示没有有效密钥,需要激活 2.管理员身份打开cmd,搜索框输入c ...

  8. Zen cart 根据数量打折插件

    Quantity Discounts 可以根据顾客购买多少来打折,很不错. 假如顾客买了3个以上的产品,就给他10%折扣,设置如下: Turn On Quantity Discount 1. In t ...

  9. Linux系统——本地yum仓库安装

    一.yum仓库概述 yum是基于rpm包管理,能够从指定的服务器自动下载rpm包并且安装,可以自动处理依赖性关系,并且一次安装所有依赖的软件包,无需繁琐地一次次下载.安装. 二.yum仓库安装的方式 ...

  10. CGlib和JDK动态代理

    一.CGlib动态代理     JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,如何实现动态代理呢,这就需要CGLib了.CGLib采用了非常底层的1:字节码技术,其原理是通过字节 ...