“字节序”是个什么鬼?

“字节序”是个什么鬼?

http://mp.weixin.qq.com/s?__biz=MjM5NTU2MTQwNA==&mid=2650652324&idx=1&sn=5502d3ab977b9894f50592266544b30c&scene=0

大端、小端引发的思考。
论顺序的重要性
1.做饭的故事今天女朋友加班,机智的她早已在昨晚准备好食材,回家只需下锅便可。谁知开会就是个无底洞,到了B1,还有B2,无穷匮也。
辛苦如她,为了能让她一回家就吃上热腾腾的饭菜,我准备亲自下厨,奉献出我的第一次。食材都已备好,我相信没有那么难,估摸着应该和我习以为常的流程处理差不多,开火 | 加食材 | 上配料 | 翻炒 | 出锅,啊哈,想想还有点小激动。
今天的晚饭是西红柿炒鸡蛋和胡萝卜炒肉,实际操作才发现,又遇到了一个大坑……
食材是这样的:
案板1号(西红柿炒鸡蛋的食材),从左向右依次放着:西红柿、鸡蛋、葱案板2号(胡萝卜炒肉的食材),从左向右依次放着:蒜、胡萝卜丝、肉
食材在案板上整齐划一依次排开,我是先放西红柿呢,还是先放鸡蛋呢,还是先放葱呢?简单沟通后得知,案板上的食材是按顺序放好的,我只需要按顺序下锅即可。听着电视哼着90年代的老歌,三下五除二,两道菜如期完成。
闻着怪味,我知道第一次就这么失败了。
等她回家,一番检讨后,才知道是顺序放错了。每道菜都应该是从右往左依次放食材,即葱->鸡蛋->西红柿。这是逗我的么!?一般人所理解的按默认顺序不应该是从左往右嘛!朋友们,到底应该是从左往右还是从右往左?
2. 剥鸡蛋的故事《格列佛游记》中记载了两个征战的强国,你不会想到的是,他们打仗竟然和剥鸡蛋的姿势有关。
很多人认为,剥鸡蛋时应该打破鸡蛋较大的一端,这群人被称作“大端(Big endian)派”。可是当今皇帝的祖父小时候吃鸡蛋的时候碰巧将一个手指弄破了。所以,他的父亲(当时的皇帝)就下令剥鸡蛋必须打破鸡蛋较小的一端,违令者重罚,由此产生了“小端(Little endian)派”。

老百姓们对这项命令极其反感,由此引发了6次叛乱,其中一个皇帝送了命,另一个丢了王位。据估计,先后几次有11000人情愿受死也不肯去打破鸡蛋较小的一端!
看到没有,仅仅是剥鸡蛋就能产生这么大的分歧,“大端”和“小端”有这么重要嘛!
字节序
1.字节字节(Byte)作为计算机世界的计量单位,和大家手中的人民币多少多少“元”一个意思。反正,到了计算机的世界,说字节就对了,使用人家的基本计量单位,这是入乡随俗。
比如,一个电影是1G个字节(1GB),一首歌是10M个字节(10MB),一张图片是1K个字节(1KB)。
2.字节序一元钱可以干嘛?啥也干不了,公交都不够坐的。一个字节可以干嘛?至少可以存一个字符。
当数据太大,一个字节存不下的时候,我们就得使用多个字节了。比如,我有两个分别需要4个字节存储的整数,为了方便说明,使用16进制表示这两个数,即0x12345678和0x11223344。有的人采用以下方式存储这个两个数字:

小端

这个方案看起来不错,但是,又有人采用了以下方式:

大端  高位低地址 节省空间

蒙圈了吧,到底该用哪一种方式来存!两种方案虽有不同,但也有共识,即依次存储每一个数字,即先存0x12345678,再存0x11223344。大家的分歧在于,对于某一个要表示的值,因为只能一个字节一个字节的存嘛,我是把值的低位存到低地址,还是把值的高位存到低地址。前者使用的是“小端(Little endian)”字节序,即先存低位的那一端(两个数字的最低位分别是0x78、0x44),如上图中的第一个图;后者使用的是“大端(Big endian)”字节序,即先存高位的那一端(两个数字的最高位分别是0x12、0x11),如上图中的第二个图。
由此也引发了计算机界的大端与小端之争,不同的CPU厂商并没有达成一致:
·x86,MOS Technology 6502,Z80,VAX,PDP-11等处理器为Little endian。
·Motorola 6800,Motorola 68000,PowerPC 970,System/370,SPARC(除V9外)等处理器为Big endian。
·ARM, PowerPC (除PowerPC 970外), DEC Alpha, SPARC V9, MIPS, PA-RISC and IA64的字节序是可配置的。
大端也好,小端也罢,就权当是个人爱好吧,只要你不影响别人就行,对不?
3.网络字节序前面的大端和小端都是在说计算机自己,也被称作主机字节序。其实,只要自己能够自圆其说是没啥问题的。问题是,网络的出现使得计算机可以通信了。通信,就意味着相处,相处必须得有共同语言啊,得说普通话,要不然就容易会错意,下了一个小时的小电影发现打不开,理解错误了!
但是每个计算机都有自己的主机字节序啊,还都不依不饶,坚持做自己,怎么办?
TCP/IP协议隆重出场,RFC1700规定使用“大端”字节序为网络字节序,其他不使用大端的计算机要注意了,发送数据的时候必须要将自己的主机字节序转换为网络字节序(即“大端”字节序),接收到的数据再转换为自己的主机字节序。这样就与CPU、操作系统无关了,实现了网络通信的标准化。突然觉得,TCP/IP协议好任性啊有木有!
为了程序的兼容,你会看到,程序员们每次发送和接受数据都要进行转换,这样做的目的是保证代码在任何计算机上执行时都能达到预期的效果。
这么常用的操作,BSD Socket提供了封装好的转换接口,方便程序员使用。包括从主机字节序到网络字节序的转换函数:htons、htonl;从网络字节序到主机字节序的转换函数:ntohs、ntohl。当然,有了上面的理论基础,也可以编写自己的转换函数。
下面的一段代码可以用来判断计算机是大端的还是小端的,判断的思路是确定一个多字节的值(下面使用的是4字节的整数),将其写入内存(即赋值给一个变量),然后用指针取其首地址所对应的字节(即低地址的一个字节),判断该字节存放的是高位还是低位,高位说明是Big endian,低位说明是Little endian。
#include int main (){  unsigned int x = 0x12345678;  char *c = (char*)&x;  if (*c == 0x78) {    printf("Little endian");  } else {    printf("Big endian");  }  return 0;}
4.身边的字节序字符编码方式UTF-16、UTF-32同样面临字节序的问题,因为他们分别使用2个字节和4个字节编码Unicode字符,一旦某个值用多个字节表示,就必须要考虑存储的顺序了。于是,采用了最简单粗暴的方式,给文件头部写几个字符,用来表示是大端呢还是小端:

这里不得不提一下UTF-8啊,明明人家是单个字节的,不存在什么字节序的问题。微软为了统一UTF-X,硬生生给他的头部也加了几个字符!是的,这几个字符就是BOM(Byte Order Mark),这就是Windows下的UTF-8。
相信很多人都被UTF-8的BOM给坑过,多了这个BOM的UTF-8文件,会导致很多问题啊。比如,写的Shell脚本,内容为#!/usr/bin/env bash,在UTF-8有BOM和UTF-8无BOM的编码下,对应的16进制为:

所以,有BOM的话,Shell解释器就报错啦。原因在于,解释器希望遇到#!/usr/bin/env bash,而使用UTF-8有BOM进行编码的内容会多了3个字节的EF BB BF。
对于UTF-8和UTF-8无BOM两种编码格式,我们更多的使用UTF-8无BOM。

转自:伯乐在线

时间: 2024-12-25 14:09:41

“字节序”是个什么鬼?的相关文章

字节序转换与结构体位域(bit field)值的读取 Part 2 - 深入理解字节序和结构体位域存储方式

上一篇文章讲解了带位域的结构体,在从大端机(Big Endian)传输到小端机(Little Endian)后如何解析位域值.下面继续深入详解字节序,以及位域存储的方式. (1) 我们知道,存储数字时,对小端机而言,数字的低位,存在低地址,高位存在高地址.大端机正相反. (2) 读取的方式,也是一样的.对于小端机,读出的低地址位作为数字的低位. (3) 此外Big-Endian/Little-Endian存储顺序,不仅仅针对字节,还针对字节内的比特位.对于小端机而言,字节内的8个比特,低地址端比

字节序

1.什么是字节序 字节序是指多字节数据在计算机内存中存储或者网络传输时各字节的存储顺序.由于数据在内存中存储的顺序与操作系统有关,因此字节在主机中的存储顺序通常称为主机序:而数据在网络中的存储顺序则称为网络序. 常见的字节序有:大端字节序(Big endian)与小端字节序(Little endian). 主机序依CPU而定:Intel x86为Little endian,Motorola680x则是Big endian. 网络序与CPU无关都是Big endian, 这是因为统一字节序有利于数

【Linux 网络编程】字节序和地址装换

(3)字节序    <1>大端字节序        最高的有效位存储于最低内存地址处,最低有效位存储于最高内存地址处.    <2>小端字节序        最高的有效位存储于最高内存地址处,最低有效位存储于最低内存地址处.  保存0x12345678       ----------------->内存地址增长的方向        12 34 56 78 大端字节序        78 56 34 12 小端字节序    <3>主机字节序        不同的主

c# 主机和网络字节序的转换 关于网络字节序和主机字节序的转换

最近使用C#进行网络开发,需要处理ISO8583报文,由于其中有些域是数值型的,于是在传输的时候涉及到了字节序的转换. 字节顺序是指占内存多于一个字节类型的数据在内存中的存放顺序,通常有两种字节顺序,根据他们所处的位置我们分别称为主机节序和网络字节序. 通常我们认为网络字节序为标准顺序,封包的时候,将主机字节序转换为网络字节序,拆包的时候要将网络字节序转换为主机字节序. 原以为还要自己写函数,其实网络库已经提供了. 主机到网络:short/int/long IPAddress.HostToNet

小端字节序与大端字节序

端模式分为:小端字节序和大端字节序,也就是字节在内存中的顺序. 小端字节序:低字节存于内存低地址:高字节存于内存高地址.如一个long型数据0x12345678 0x0029f458 0x78 0x0029f459 0x56 0x0029f45a 0x34 0x0029f45b 0x12 在以上数据存放于内存中的表现形式中,0x0029f458 < 0x0029f459 < 0x0029f45a < 0x0029f45b, 可以知道内存的地址是由低到高的顺序:而数据的字节也是由低到高的,

实现两个字节序的交换

实现两个字节序的交换例如:300=0X012C,交换之后为0X2C01 1 /******************************************************************************* 2 * Function Name : exchangeBytes 3 * Description : 模拟的htons 或者 ntohs,如果系统支字节序更改可直接替换成系统函数 4 * Input : value 5 * Output : None 6 *

内存对齐,大端字节 &nbsp; 序小端字节序验证

空结构体:对于空结构体,就是只有结构体这个模子,但里面却没有元素的结构体. 例: typedef struct student { }std: 这种空结构体的模子占一个字节,sizeof(std)=1. 柔性数组: 结构体中最后一个元素可以是一个大小未知的数组,称作柔性数组成员,规定柔性数组前面至少有一个元素. typedef struct student { int i; char arr[];     //柔性数组成员 }std: sizeof(std)=4; sizeof求取该结构体大小是

对于字节序小端和大端的思考

最近公司处理器要换核,由小端处理器ARM换成大端处理器POWERPC,bootloader以及kernel的移植工作交给了我,这是一个很有挑战的工作,自己也非常兴奋. 如此一来,当今主流的嵌入式处理器(MIPS ARM PPC)也都算接触过啦. 这几天开始动手做移植,首先要解决的是大小端的差异,进过学习思考,感觉大小端还是很有研究的必要,自己的思考总结记录在此,与大家分享,以备后用. 从网上可以查到的大小端的解释,小端是低端数据存放在低端地址,大端是高端数据存在低端地址.大小端真的就这么简单吗,

1.socket编程:socket编程,网络字节序,函数介绍,IP地址转换函数,sockaddr数据结构,网络套接字函数,socket相关函数,TCP server和client

 1  Socket编程 socket这个词可以表示很多概念: 在TCP/IP协议中,"IP地址+TCP或UDP端口号"唯一标识网络通讯中的一个进程,"IP 地址+端口号"就称为socket. 在TCP协议中,建立连接的两个进程各自有一个socket来标识,那么这两个socket组成的socket pair就唯一标识一个连接.socket本身有"插座"的意思,因此用来描述网络连 接的一对一关系. TCP/IP协议最早在BSD UNIX上实现,