大端小端是什么?如何区分?



    今天我们谈谈计算机中的大端小端以及网络中的大端小端。参考了网上好多资料以后,从众多资料中我也按照自己的理解方式,总结一下。



学习一个新东西:我们依然是先了解一下大端小端的历史:

讲故事 这个就需要求救一下度娘,以下故事来自度娘,真假我也不知道,权当听故事:

“大端”和“小端”可以追溯到1726年的Jonathan Swift的《格列佛游记》,其中一篇讲到有两个国家因为吃鸡蛋究竟是先打破较大的一端还是先打破较小的一端而争执不休,甚至爆发了战争。1981年10月,Danny Cohen的文章《论圣战以及对和平的祈祷》(On holy wars and a plea for peace)将这一对词语引入了计算机界。这么看来,所谓大端和小端,也就是big-endian和little-endian,其实是从描述鸡蛋的部位而引申到计算机地址的描述,也可以说,是从一个俚语衍化来的计算机术语。稍有些英语常识的人都会知道,如果单靠字面意思来理解俚语,那是很难猜到它的正确含义的。在计算机里,对于地址的描述,很少用“大”和“小”来形容;对应地,用的更多的是“高”和“低”;很不幸地,这对术语直接按字面翻译过来就成了“大端”和“小端”,让人产生迷惑也不是很奇怪的事了。

听完了故事,这下让我们来看什么是大端小端:依然沿袭过去用图讲解,来理解结构:

现实生活中我们写的数据时左边位权高,右边的位权低,比如123,1表示的就是100,对吧,因为计算机只认识0和1,这里,我把它换算成2进制形式:上图是1的二进制形式。这下就要引出今天我们的主角大端小端,most significant (最高有效位)在低地址位就是大端,(least significat) 在高地址位就是小端,现在我们大多数的计算机都是采用八位一个字节,所以当如果把1按照第一个存储的话就是大端,第二个就是小端。上边用红色标记起来的就是理解的重点。

还有就是关于字符串是怎么区分的,比如说:char *ch ="12345",对于字符串,是没有什么大端小端的,5一定是在高地址存放的。


网络中的大端与小端

可能上面的内容你已经搞清楚了,但是当你看一些关于网络或者的资料时发现又有什么网络字节序神马的,然后又糊涂了,让我们一起来破除关于网络字节序列这些神马的浮云。

了解网络是怎样发送数据的?
我们使用的网络协议很多都是基于socket的,所以我们基于socket来讲,在socket规范中发送数据是 这个方法

send(Socket soc, char * buf, len , 0);
 第一个参数是对方的socket,也就是地址
 第二个参数是 一个字符指针,也就是要发送的内容存放的地址
 第三个是发送数据的长度
 第四个是和选择协议相关的,一般设为0

所以这里我们看到在底层发送数据的方法里面根本没有和什么大端小端有关系的东西,发送的函数只关心你要给老子发送的东西在哪儿,发多少,其他一概不管,好,现在用一个场景说明一下。程序员A把一个金额发给程序员B,这个金额是B欠A钱的金额。

//A发给B,这是B欠我A的数目 ,是1500元,下面是十六进制写法short a = 0x05DC;//于是A就send(sock, (char *)&a,2,0);12341234

接收和发送的函数方法参数是一样的
recv(Socket soc, char * buf, len , 0);
好,这个数目发完了,B接收的时候用下面的代码

char ownMoney [2];recv(Socket soc,ownMoney, 2 , 0);1212

好了,数据发送和接受都完成了,到这里为止,和大小端半毛钱关系都没有,接下来就有了。这B想看看到底欠了A多少钱了,用下面的代码接收。

int total = ((ownMoney[0] << 8) | (ownMoney[1] & 0xFF )   &0xFF );11

一看吓了一跳 56325,这就出大问题了,B心想,A是我铁哥们儿,肯定不会骗我,肯定是那个地方数据出错了,于是有了下面的对话

B:兄弟你电脑CPU是什么的?
 A:是intel的啊
 B:发送数据的时候有做什么处理吗?
 A:没有做任何处理
 B:额,我明白了

刚好B的机器也是Intel的CPU,B找到原因之后背了一遍我编写的口诀,低地址是低位是小端,低低地址是高位为大端。

B分析了一下数据的发送流程,A发送两个字节的short型数据,因为A是小端所以,先发送过来的是低位数据,后发送的是高位,我先接收的也是低位,后接收的是高位。

B修改程序后

int total = (ownMoney[0]  &0xFF ) | ( (ownMoney[1] << 8) & 0xFF )   );11

一看,额,1500,心里松了一口气,这就对了。我们来看看出现刚刚这个问题的原因。
A是 Intel CPU (小端机器), 0x05DC这个数,低地址存放的是DC,高地址是05, B接受了放在 字符数组中, 因为B也是小端机器,B还原数据的时候是在低地址放在了高位,也就是0xDC,这是 不对的。

那总不能每次发送数据都问一下别人是什么CPU吧?

于是人们就约定将数据的低地址处放数据的高位(也叫大端法),于是A就遵循了这个约定, 发送之前将数据位置改了一下,因为之前低地址放的是低位。之前A的数据是这样放的

低地址 高地址
DC 05

因为约定采用大端法发送数据,所以要改成下面这样

低地址 高地址
05 DC
//这样改变位置的代码short a = 0x05DC;//用一个字符指针指向a char* pointerOfA = (char *)&a;//把数据的低位值保存在一个变量里,也就是 DCchar temp = *(pointerOfA );//把高位的值放在低位 *pointerOfA = *(pointerOfA +1);*(pointerOfA +1) = temp;//再发送send(sock, pointerOfA ,2,0);1234567891011121312345678910111213

如果遵守约定,B就不用问A你的机器是什么类型了,但是还有一个问题,因为B的机器类型可能是大端也可能是小端,那接受数据的时候还要去判断机器类型,这也太麻烦了,对,没错,底层的网络处理就是这么麻烦。

 




以上总结是本人参考了网上的资料后自己整理发布的,如果原博主有问题,可以联系本人。

时间: 2024-11-03 22:55:33

大端小端是什么?如何区分?的相关文章

大端/小端,高字节/低字节,高地址/低地址,移位运算

其实大端小端的概念比较好理解的,大端:数据的高字节存放在内存的低地址中. 数组的声明方式是从左往右,地址逐渐增大. int8_t a[] = { 1, 2, 3 }; for (int i = 0; i < 3; i++) printf("a[%d]: %p\n", i, &a[i]); a[0]: 0x7ffce52cf290 a[1]: 0x7ffce52cf294 a[2]: 0x7ffce52cf298 int8_t是<stdint.h>定义的跨平台数

大端小端

什么是大端小端 所谓的大端模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中: 所谓的小端模式,是指数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中. 80c51,msp430,stm32 80c51是大端 msp4340采用小端模式读写存储器 如果是STM32F101xx和STM32F103xx仅支持小端模式,虽然Cortex-M3是大小都支持的.

大端小端的概念

对于一个由2个字节组成的16位整数,在内存中存储这两个字节有两种方法:一种是将低序字节存储在起始地址,这称为小端(little-endian)字节序:另一种方法是将高序字节存储在起始地址,这称为大端(big-endian)字节序.术语"小端"和"大端"表示多个字节值的哪一端(小端或大端)存储在该值的起始地址. #define  _CRT_SECURE_NO_WARNINGS 1 #include <stdlib.h> #include <stdio

大端小端的判断

大端小端的判断 1.联合体(共用体) union U { char s[9]; int n; double d; }; 联合体和结构体的定义和使用是一样的,就不详细的赘述.必须要记住:联合体所有的成员变量都是共享同一块内存的,从相同的起始地址进行赋值.也就是给联合体的一个成员变量赋值的时候,就会改变其他成员变量的值. 联合体的大小: 对于计算一个联合体的大小(共用体)来说,不同的编译器计算的结果是不同的. VS2013: union U { char s[9]; int n; double d;

【转】轻松记住大端小端的含义(附对大端和小端的解释)

原文网址:http://www.cnblogs.com/wuyuegb2312/archive/2013/06/08/3126510.html 或许你曾经仔细了解过什么是大端小端,也动手编写了测试手头上的机器上是大端还是小端的程序,甚至还编写了大端小端转换程序:但过了一段时间之后,当你再看到大端和小端这两个字眼,你的脑中很快浮起了自己曾经做过的工作,却总是想不起究竟哪种是大端.哪种是小端,然后又去查以前写的记录?更让人不快的是,这种经历反反复复,让你十分困扰.如果你和以前的笔者一样,有过这种不快

从大端小端开始

首先附下百科的解释. 大端模式:数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放: 小端模式:数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致. 概念上并不难理解,只是有时容易混淆. 个人的记忆方法是:将数据当做一个字符串顺序处理,从左往右看,如果每个字符(数

如何判断大端小端?

一.最简单的做法: 参考(深入理解计算机系统中文版第二版,P28,show_bytes) 转化成usigned char*的byte_pointer: 然后遍历输出每个字节的值,即可判断. 输入可以是任意一个数. 类似于:http://blog.csdn.net/yuucyf/article/details/7193148 二.利用联合 由于联合是共享地址的,所以可以采用如下方式: 1 #include <iostream> 2 using namespace std; 3 4 union 5

大端小端格式详解

1. 什么是大端,什么是小端: 所谓的大端模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中: 所谓的小端模式,是指数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中. 2.为什么会有大小端: 为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit.但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于8位的处

栈增长方向与大端/小端问题

转:http://www.cnblogs.com/xkfz007/archive/2012/06/22/2558935.html 栈增长和大端/小端问题是和CPU相关的两个问题.在内存管理中,与栈对应是堆.对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向:对于栈来讲,它的生长方式是向下的,是向着内存地址减小的方向增长.在内存中,“堆”和“栈”共用全部的自由空间,只不过各自的起始地址和增长方向不同,它们之间并没有一个固定的界限,如果在运行时,“堆”和 “栈”增长到发生了相互覆盖时,称为“