深入理解计算机系统-之-数值存储(一)-CPU大端和小端模式详解

大端与小端



在嵌入式开发中,大端(Big-endian)和小端(Little-endian)是一个很重要的概念。

MSB与LSB



最高有效位(MSB)指二进制中最高值的比特。在16比特的数字音频中,其第1个比特便对16bit的字的数值有最大的影响。例如,在十进制的15,389这一数字中,相当于万数那1行(1)的数字便对数值的影响最大。比较与之相反的“最低有效位”(LSB)。

LSB(Least Significant Bit),意为最低有效位;MSB(Most Significant Bit),意为最高有效位

若MSB=1,则表示数据为负值,若MSB=0,则表示数据为正。
MSB高位前导,LSB低位前导。

谈到字节序的问题,必然牵涉到两大CPU派系。那就是Motorola的PowerPC系列CPU和Intel的x86系列CPU。PowerPC系列采用big endian方式存储数据,而x86系列则采用little endian方式存储数据。那么究竟什么是big endian,什么又是little endian呢?

其实big endian是指低地址存放最高有效字节(MSB)
而little endian则是低地址存放最低有效字节(LSB)。

MSDN中关于LE和BE的解释

Byte Ordering Byte ordering Meaning
big-endian The most significant byte is on the left end of a word.
little-endian The most significant byte is on the right end of a word.

这里这个最重要的字节可以解释成值的最高位,如果换成是钱的话就是最值钱的那一位

Big endian machine: It thinks the first byte it reads is the biggest.
Little endian machine: It thinks the first byte it reads is the littlest.

比如我有1234元人民币,最值钱的是1000元,最不值钱的是4元,那么这个1就是最重要的字节

下面我们详细讲下大小端模式的问题

端模式(Endian)



端模式(Endian)的这个词出自Jonathan Swift书写的《格列佛游记》。这本书根据将鸡蛋敲开的方法不同将所有的人分为两类,从圆头开始将鸡蛋敲开的人被归为Big Endian,从尖头开始将鸡蛋敲开的人被归为Littile Endian。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开。在计算机业Big Endian和Little Endian也几乎引起一场战争。在计算机业界,Endian表示数据在存储器中的存放顺序。

大端



大端(Big-endian)模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中

这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;这种存放方式符合人类的正常思维

小端



小端(Little-endian)模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中

这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致。

总结



采用大小模式对数据进行存放的主要区别在于在存放的字节顺序,大端方式将高位存放在低地址,小端方式将高位存放在高地址。采用大端方式进行数据存放符合人类的正常思维,而采用小端方式进行数据存放利于计算机处理。到目前为止,采用大端或者小端进行数据存放,其孰优孰劣也没有定论。

有的处理器系统采用了小端方式进行数据存放,如intel芯片是小端(修改分区表时要注意)。

有的处理器系统采用了大端方式进行数据存放,如IBM半导体和Freescale的PowerPC处理器以及一些常见的单片机芯片。不仅对于处理器,一些外设的设计中也存在着使用大端或者小端进行数据存放的选择。

特别的intel x86的CPU使用的是LE(Windows中称为“主机字节序”),而SocksAddr中使用的则是BE(就是“网络字节序”),所以在使用网络编程时需要使用htns,htnl,nths,nthl来倒字节序。

因此在一个处理器系统中,有可能存在大端和小端模式同时存在的现象。这一现象为系统的软硬件设计带来了不小的麻烦,这要求系统设计工程师,必须深入理解大端和小端模式的差别。大端与小端模式的差别体现在一个处理器的寄存器,指令集,系统总线等各个层次中。

示例分析



假如现有一32位int型数0x12345678
那么

其MSB(Most Significant Byte,最高有效字节)为0x12,
其LSB (Least Significant Byte,最低有效字节)为0x78

地址偏移 大端模式 小端模式
0x00 12(OP0) 78(OP3)
0x01 34(OP1) 56(OP2)
0x02 56(OP2) 34(OP1)
0x03 78(OP3) 12(OP0)

也可以看下面这个图

我们可以看到看到

  • 大端(Big-endian)模式下数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,特别的MSB最高有效字节为0x12存放在低字节
  • 小端(Little-endian)模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,,特别的LSB最高有效字节为0x78存放在低字节

填写数据时我们可以发现

BE big-endian 大端模式
最直观的字节序
地址低位存储值的高位
地址高位存储值的低位
为什么说直观,不要考虑对应关系
只需要把内存地址从左到右按照由低到高的顺序写出
把值按照通常的高位到低位的顺序写出
两者对照,一个字节一个字节的填充进去

LE little-endian 小端模式
最符合人的思维的字节序
地址低位存储值的低位
地址高位存储值的高位
怎么讲是最符合人的思维的字节序,是因为从人的第一观感来说
低位值小,就应该放在内存地址小的地方,也即内存地址低位
反之,高位值就应该放在内存地址大的地方,也即内存地址高位

程序分析



如何编写程序测试看CPU使用的是大端模式还是小端模式
下面这段代码可以用来测试一下你的编译器是大端模式还是小端模式:

#include<stdio.h>

int main()

{

    short int x;

    char x0,x1;

    x=0x1122;

    x0=((char *)&x)[0];  //低地址单元

    x1=((char *)&x)[1];  //高地址单元

    printf("x0=0x%x,x1=0x%x",x0,x1);// 若x0=0x11,则是大端; 若x0=0x22,则是小端......

    return 0;

}

我们把他封装成函数的形式

//返回值:大端返回1,小段返回0

int check_end()
{
    int   i = 0x12345678;
    char *c = (char *)&i; 

    return (*c == 0x12);
}

也可以

//返回值:大端返回1,小段返回0

int CheckEnd()
{
    union
    {
        int a;
        char b;
    }u;

    u.a = 1;
    if (u.b == 1)
        return 0;
    else
        return 1;
}

转载:http://blog.csdn.net/gatieme/article/details/50642756

时间: 2024-09-30 03:27:32

深入理解计算机系统-之-数值存储(一)-CPU大端和小端模式详解的相关文章

深入理解计算机系统-之-数值存储(二)--C程序打印变量的每一字节或者位

大端与小端 前面我们提到了依据CPU端模式的不同,数据的存储顺序也不一样. 采用大小模式对数据进行存放的主要区别在于在存放的字节顺序,BE big-endian 大端模式 ,最直观的字节序 ,地址低位存储值的高位,地址高位存储值的低位 ,不需要考虑对应关系,只需要把内存地址从左到右按照由低到高的顺序写出 ,把值按照通常的高位到低位的顺序写出 ,两者对照,一个字节一个字节的填充进去 LE little-endian 小端模式,最符合人的思维的字节序,地址低位存储值的低位,地址高位存储值的高位 ,怎

深入理解JavaScript系列(29):设计模式之装饰者模式详解

 这篇文章主要介绍了深入理解JavaScript系列(29):设计模式之装饰者模式详解,装饰者用用于包装同接口的对象,不仅允许你向方法添加行为,而且还可以将方法设置成原始对象调用(例如装饰者的构造函数),需要的朋友可以参考下     介绍 装饰者提供比继承更有弹性的替代方案. 装饰者用用于包装同接口的对象,不仅允许你向方法添加行为,而且还可以将方法设置成原始对象调用(例如装饰者的构造函数). 装饰者用于通过重载方法的形式添加新功能,该模式可以在被装饰者前面或者后面加上自己的行为以达到特定的目的.

深入理解计算机系统-之-数值存储(六)--以不同的方式窥视内存

浮点数写,整数读 好了知道了浮点数的存储方式,那么我们的问题来了,如果我们定义了一个浮点数,那么如果以整数的格式去读取它,会发生什么奇妙的现象 代码示例 我们对上一篇文章中修改main函数为如下形式 我们定义了变量float f = 9.0f, 然后用一个整形指针去读它,由于32位机器上int和float类型的大小是一致的,不会存储访问越界(即使是64位机器,int也不一定为不是32位,因为这个不仅跟机器字长相关,还跟编译器的处理方式相关) #include <stdio.h> #includ

深入理解计算机系统-之-数值存储(三)-- 原码、反码、补码和移码详解

原码 如果机器字长为n,那么一个数的原码就是用一个n位的二进制数,其中最高位为符号位:正数为0,负数为1.剩下的n-1位表示概数的绝对值. PS:正数的原.反.补码都一样:0的原码跟反码都有两个,因为这里0被分为+0和-0. 原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值. 比如如果是8位二进制: [+1]原 = 0000 0001 [-1]原 = 1000 0001 例如: X=+101011 , [X]原= 00101011 X=-101011 , [X]原= 1010

深入理解JavaScript系列(37):设计模式之享元模式详解_基础知识

介绍 享元模式(Flyweight),运行共享技术有效地支持大量细粒度的对象,避免大量拥有相同内容的小类的开销(如耗费内存),使大家共享一个类(元类). 享元模式可以避免大量非常相似类的开销,在程序设计中,有时需要生产大量细粒度的类实例来表示数据,如果能发现这些实例除了几个参数以外,开销基本相同的 话,就可以大幅度较少需要实例化的类的数量.如果能把那些参数移动到类实例的外面,在方法调用的时候将他们传递进来,就可以通过共享大幅度第减少单个实例 的数目. 那么如果在JavaScript中应用享元模式

深入理解JavaScript系列(36):设计模式之中介者模式详解_基础知识

介绍 中介者模式(Mediator),用一个中介对象来封装一系列的对象交互.中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互. 主要内容来自:http://www.addyosmani.com/resources/essentialjsdesignpatterns/book/ 正文 软件开发中,中介者是一个行为设计模式,通过提供一个统一的接口让系统的不同部分进行通信.一般,如果系统有很多子模块需要直接沟通,都要创建一个中央控制点让其各模块通过该中央控制点进行

深入理解JavaScript系列(38):设计模式之职责链模式详解_基础知识

介绍 职责链模式(Chain of responsibility)是使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系.将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理他为止. 也就是说,请求以后,从第一个对象开始,链中收到请求的对象要么亲自处理它,要么转发给链中的下一个候选者.提交请求的对象并不明确知道哪一个对象将会处理它--也就是该请求有一个隐式的接受者(implicit receiver).根据运行时刻,任一候选者都可以响应相应的请求,候选者的数目是任意

深入理解JavaScript系列(26):设计模式之构造函数模式详解

 这篇文章主要介绍了深入理解JavaScript系列(26):设计模式之构造函数模式详解,本文讲解了基本用法.构造函数与原型.只能用new吗?.强制使用new.原始包装函数等内容,需要的朋友可以参考下     介绍 构造函数大家都很熟悉了,不过如果你是新手,还是有必要来了解一下什么叫构造函数的.构造函数用于创建特定类型的对象--不仅声明了使用的对象,构造函数还可以接受参数以便第一次创建对象的时候设置对象的成员值.你可以自定义自己的构造函数,然后在里面声明自定义类型对象的属性或方法. 基本用法 在

深入理解JavaScript系列(19):求值策略(Evaluation strategy)详解

 这篇文章主要介绍了深入理解JavaScript系列(19):求值策略(Evaluation strategy)详解,本文讲解了一般理论.按值传递.按引用传递.按共享传递(Call by sharing).按共享传递是按值传递的特例等内容,需要的朋友可以参考下     介绍 本章,我们将讲解在ECMAScript向函数function传递参数的策略. 计算机科学里对这种策略一般称为"evaluation strategy"(大叔注:有的人说翻译成求值策略,有的人翻译成赋值策略,通看下面