应该说没做底层开发(硬件或驱动)的人很可能不会彻底理解大小端的概念,大小端不是简单的一句“大端在前”还是“小端在前”能够概括的问题。在cpu, 内存, 操作系统, 编译选项, 文件,网络传输中均有大小端的概念,这些东西加在一起,就很容易把人搞晕。我自己就晕过很久。

为方便说明,再做一些定义:

(1) 内存

可以存储若干个单元数据的物理设备,每个单元存储1个字节,每个单元有一个地址,其地址线程增长。为方便说明,假设内存地址从 0000:0000 一直增加到FFFF:FFFF。

用一个带箭头的直线表示地址的增长方向,例如

-------------------------->

表示左边的数据处于低地址,右边的数据处于高地址。

(2) U32整型

对于unsigned int的变量,计算机是以32bits存储的,即连续的4个字节。比如说,对一个值为0x11223344的整数,在内存中的排列方式可能为:

-------------------------->

11  22  33  44 (大端)

也可能为

44  33  22  11 (小端)

从CPU说起

在有了上述定义之后,开始讲大小端的起源。这得从CPU说起,我们知道CPU要从内存中加载程序数据来运行,CPU要对数字进行运算。那么,CPU在从内存加载4个字节的数据之后,要把它作为一个数字来运算。那它是怎么看待这个数字的呢?

-------------------------->

11  22  33  44

有的CPU认为它是0x11223344,有的CPU认为它是0x44332211。所以CPU就分为两类:Big-Endian和Little-Endian, 认为它是0x11223344的就是Big-Endian,认为它是0x44332211的就是Little-Endian。

有人会为,CPU的“认为”是什么意思。这其实物理上的电路问题,CPU的所有运算都是通过电路完成,其连接逻辑已经决定了它是按大端运算还是按小端运算。

程序

在知道了CPU的大小端之后,我们要写一个程序让CPU来运行,那么显然,程序必须遵从CPU的大小端。程序最终会load到内存里,所以其大小端的定义要和CPU一致。

具体得,程序都是有很多条指令构成的,每条指令4个字节。假设程序里有一个指令ADD,机器码为0xAABBCCDD。显然,只有内存里按顺序AABBCCDD出现时,CPU才能理解为是ADD。不然CPU根据不能辨识这条指令。

文件

程序是放在哪的呢?放在文件里的,文件也是线性的。所以可以这么认为,文件就是内存的一份映像,其数据内容是完全一样的(实际上不一样,但可以这么理解)。所以,如果cpu是大端,那么内存中的程序也必须是大端,保存程序的文件也必须是大端。

程序的编译

程序从哪来的?编译器编出来的。我们在用gcc来编译一个程序时,可能没有发现任何关于Endian的参数设置。这是因为有一个默认选项被指定义了。这可以参考gcc/ld相关的文档,关于link script的描述。在link script里是可以指定endian的。

  从上面可以看出,cpu、程序、编译过程这一套东西,其大小端都必须是一致的。这里就简称为系统的大小端。

网络传输

网络传输数据时需要考虑大小端。例如,想发送一个U32的数字给对方,需要连续发送4个字节。那么是才发送高字节,还是先发送低字节呢?一般来说,网络上一般是先传送高字节,即大端,又称为网络字节序。例如,在传递0x12345678的时候,会先传0x12, 再传0x34, 再0x56, 再0x78。

在代码判断大小端

inline bool IsLittleEndian()
{
    unsigned int a = 0x01;
    return (*((unsigned char*)&a) == 1);
}

系统无关的写法

在传送和保存数据时,可以写一份不管系统是大端还是小端、结果都相同的代码。这是用移位来实现的。比如,我们从网络上接收到4个字节,想把它转成一个U32。

U8 buf[4]; // 接收到4个字节, 按大端传递

U32 v = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3];

一种错误的写法

在做编解码的时候会经常遇到关于大小端的问题,而写错的人大有人在,协议定义不好的也大有人在。一般来说,只要发现一个协议把数据定义成小端,那么我一般猜到了作者想干什么了。例如, 定义一个协议,发送以下数据,以小端发送。

U8  a

U8  b

U16  c

U32  d

那么程序基本上会这么写代码:

struct Msg

{

U8 a;

U8 b;

U16 c;

U32 d;

};

U8 buf[8];

Msg msg;

memcpy(&msg, buf, 8);

那intel的机器上,会发现这样刚好是对的。但是我要说这是不正确的写法。

BIT有大小端吗?

在软件编程领域,大小端总是按BYTE计算的,永远无需考虑BIT的大小端。因为数据的最小单元是BYTE,在物理环节中其顺序都固定好了,永远对的上。正因为如此,我们可以用位域来接收按位定义的信息,而不必担心大小端。如在PES的头部:

struct Flags

{

TS_UINT8 original_or_copy : 1;
  TS_UINT8 copyright : 1;
  TS_UINT8 alignment_indicator : 1;
  TS_UINT8 priority : 1;
  TS_UINT8 scrambling_control : 2;
  TS_UINT8 not_used : 2;

}

但要注意的是,这仅限于字节之内的情形。

 
转载链接:http://blog.csdn.net/xiaojun111111/article/details/42294223
其他相关链接: 

ENDIAN的由来及BIG-EDIAN 和LITTLE-ENDIAN

一、引子   在各种计算机体系结构中,对于字节、字等的存储机制有所不同,因而引发了 计算机通信领域中一个很重要的问题,即通信双方交流的信息单元(比特、字节、 字、双字等等)应该以什么样的顺序进行

字节顺序:高位优先(big-endian)和低位优先(little-endian)

字节顺序是指占内存多于一个字节类型的数据在内存中的存放顺序,通常有小端、大端两种字节顺序。小端字节序指低字节数据存放在内存低地址处,高字节数据存放在内存高地址处;大端字节序是高字节数据存放在低地址处

大小端 Big-Endian 与 Little-Endian的更多相关文章

  1. 大端和小端(Big endian and Little endian)

    一.大端和小端的问题 对于整型.长整型等数据类型,Big endian 认为第一个字节是最高位字节(按照从低地址到高地址的顺序存放数据的高位字节到低位字节):而 Little endian 则相反,它 ...

  2. 大端和小端(big endian little endian)

    一.大端和小端的问题 对于整型.长整型等数据类型,Big endian 认为第一个字节是最高位字节(按照从低地址到高地址的顺序存放数据的高位字节到低位字节):而 Little endian 则相反,它 ...

  3. 整型,长整型,无符号整型等 大端和小端(Big endian and Little endian)

    一.大端和小端的问题 对于整型.长整型.无符号整型等数据类型,Big endian 认为第一个字节是最高位字节(按照从低地址到高地址的顺序存放数据的高位字节到低位字节):而 Little endian ...

  4. 03大端和小端(Big endian and Little endian)

    1.大端和小端的问题 ​ 对于整型.长整型等数据类型,Big endian 认为第一个字节是最高位字节(按照从低地址到高地址的顺序存放数据的高位字节到低位字节),而 Little endian 则相反 ...

  5. CPU的大小端模式

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

  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. 字符编码(ASCII,Unicode和UTF-8) 和 大小端

    本文包括2部分内容:“ASCII,Unicode和UTF-8” 和 “Big Endian和Little Endian”. 第1部分 ASCII,Unicode和UTF-8 介绍 1. ASCII码 ...

  10. C# 网络通信大小端转换类

    本篇文章主要介绍了"C# 网络通信大小端转换类" using System;namespace Framework.NetPackage.Common { /// <summ ...

随机推荐

  1. BZOJ1076:[SCOI2008]奖励关——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=1076 https://www.luogu.org/problemnew/show/P2473 你正在 ...

  2. CodeForces - 158B.Taxi (贪心)

    CodeForces - 158B.Taxi (贪心) 题意分析 首先对1234的个数分别统计,4人组的直接加上即可.然后让1和3成对处理,只有2种情况,第一种是1多,就让剩下的1和2组队处理,另外一 ...

  3. 放弃采用Mycat的条件

    Mycat::一个新颖的数据库中间件产品 设计使用Mycat时: 满足以下任意一条,请考虑放弃使用MyCat 有非分片字段查询 有分页排序 进行表JOIN操作,除非要确保两个表的关联字段具有相同的数据 ...

  4. bzoj1014: [JSOI2008]火星人prefix(splay+hash+二分)

    题目大意:一个字符串三个操作:①求两个后缀的LCP②插入一个字符③修改一个字符. 前几天刚学了hash+二分求lcp,就看到这题. 原来splay还能这么用?!原来splay模板这么好写?我以前写的s ...

  5. 51nod 1172 Partial Sums V2 卡精度的任意模数FFT

    卡精度的任意模数fft模板题……这道题随便写个表就能看出规律来(或者说考虑一下实际意义),反正拿到这题之后,很快就会发现他是任意模数fft模板题.然后我就去网上抄了一下板子……我打的是最土的任意模数f ...

  6. @RequestParam 注解的使用

    @RequestParam 注解的使用 前言 在SpringMvc后台进行获取数据,一般是两种. 1.request.getParameter(“参数名”) 2.用@RequestParam注解获取 ...

  7. [实战篇入门]02-POI简单创建Excel

    周日的小讲堂要讲到这里,趁中午时间写点东西,记录昨天晚上完成的东西,在这里只是简单的介绍如何创建对于样式问题,我不过多的说,因为之后的教程会使用模版方式搞定! 在学习这段代码的时候,希望各位访问Apa ...

  8. 【转】Pyhton 单行、多行注释符号使用方法及规范

    转自:Pyhton 单行.多行注释符号使用方法及规范 python中的注释有多种,有单行注释,多行注释,批量注释,中文注释也是常用的.python注释也有自己的规范,在文章中会介绍到.注释可以起到一个 ...

  9. Rabbit MQ 面试题相关

    项目中的MQ: #rabbitmq spring.rabbitmq.host=127.0.0.1 主机 spring.rabbitmq.port=5672 端口 spring.rabbitmq.use ...

  10. HDU5875 Function

    题意:给定序列,有m个区间的询问,求每个询问a[l]%a[l+1]...%a[r]后的值.(N<=10^5) 思路:这题如果使用线段树,可能会由于姿势和卡常数原因TLE,由于数据好像比较奇怪(? ...