zoukankan      html  css  js  c++  java
  • Qt大小端

    转: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.文件存储中的模式

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

    [cpp] view plain copy
     
    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的第一个字节即可。

    五、大端和小端的检测

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

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

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

    [cpp] view plain copy
     
    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>包含了大端小端转换的几个函数

    [cpp] view plain copy
     
    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)  

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

    [cpp] view plain copy
     
    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()函数,和前者类似。对于大端模式的计算机进行转换,对于小端模式的计算机只是读取数据。

    [cpp] view plain copy
     
    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只针对有符号和无符号的整型,对于浮点型(一般也不会用到),需要进行强制类型转换。

  • 相关阅读:
    (转)轻松应对IDC机房带宽突然暴涨问题
    (转)老男孩:Linux企业运维人员最常用150个命令汇总
    (转)cut命令详解
    (转)Awk使用案例总结(运维必会)
    (转)Nmap命令的29个实用范例
    BigPipe学习研究
    js正则大扫除
    ffff表单提交的那点事
    高并发订单操作处理方法
    订单号的处理
  • 原文地址:https://www.cnblogs.com/judes/p/8349834.html
Copyright © 2011-2022 走看看