计算机中的大端法和小端法

时隔一年时间再一次看 CSAPP(Computer Systems: A Programmer’s Perspective, 2/E, 中文译名:深入理解计算机系统),正是这本书把我带入到计算机世界。在读第三章时某段时,对第二章中寻址和字节顺序中所讲的大端法与小端法的一些细节感到困惑。于是查了一些资料,主要是 Wikipedia 上的 Endianness 词条,在这里做一下总结。

基本概念

在计算机内存中,通常是以字节(Byte),也就是 8 个位(Bit)为基本存储单元(也有以 16 位为基本存储单元的)。对于跨越多个字节的数据类型(比如 int 长 4 个字节),如何在内存中对这些字节进行排序有两种常见的方法:大端法和小端法。不管是大端法还是小端法存储,计算机在内存中存放数据的顺序都是从低地址到高地址,所不同的是首先取低字节的数据存放在低地址还是取高字节数据存放在低地址。

  • 若首先取高字节的数据存放在低地址,则是大端法;
  • 若首先取低字节的数据存放在低地址,则是小端法。

Endianness

至于大小端法,只是一种习惯,没有优劣之分,只可惜在计算机发展史上没有形成一个统一的标准。

词源

大端法和小端法的英语原文分别为 Big-endians 和 Little-endians, endian 一词来自乔纳森·斯威夫特的小说格列佛游记。下面摘自《深入理解计算机系统》

旁注:“endian”的起源

下面就是Jonathan Swift在1726年如何描述大、小端之争的历史的:

“……我下面要告诉你的是,Lilliput和Blefuscu这两大强国在过去三十六个月里一直在苦战。战争开始是由于一下原因:我们大家都认为,吃鸡蛋前,原始的方法是打破鸡蛋较大的一端,可是当今皇帝的祖父小时候吃鸡蛋,一次按原来的方法打鸡蛋时碰巧将一个手指弄破了,因此他的父亲,当时的皇帝,就下了一道命令,命令全体臣民吃鸡蛋时打破鸡蛋较小的一端,违令者重罚。老百姓们对这项命令极为反感。历史告诉我们,由此曾发生过六次叛乱,其中一个皇帝送了命,另一个丢了王位。这些叛乱大多都是由Blefuscu的国王大臣们煽动起来的。叛乱平息后,流亡的人总是逃到那个帝国去寻救避难。据估计,先后几次有一万一千人情愿受死也不肯去打破鸡蛋较小的一端。关于这一争端,曾出版过几百本大部著作,不过大端派一直是受禁的,法律也规定该派的任何人不得做官。”(《格列佛游记》第一卷第4章)

在他那个时代,Swift是在讽刺英国(Lilliput)和法国(Blefuscu)之间持续的冲突。Danny Cohen,一位网络协议的早期开创者,第一次使用这两个术语来指代字节顺序,后来这个术语被广泛接纳了。

字节序还是位序

大端法和小端法指的是字节在内存中存储时的排列规则,而不是数据中的位的排列规则。也有以位序排列的机器,但很少见。另外,再次明确一下,大端法或小端法是数据在存储时的表现,而不是在寄存器中参与运算时的表现。

浮点数的字节序

在所有机器上,浮点数在存储时的字节顺序是和整数的字节顺序一样的,所以在进行网络传输时,可以把浮点数当作整数进行字节序转换。但在历史上,曾经有段时间因为 IEEE 并没有规定浮点数在网络上传送的标准,所以浮点数都是以大端法进行存储的。

判断大小端法的方法

Linux 操作系统中使用了一个联合体(union)和宏进行判断

static union { char c[4]; unsigned long l; } endian_test = { { 'l', '?', '?', 'b' } };

#define ENDIANNESS ((char)endian_test.l)

相当巧妙,不是吗?

网络上的字节序

对于大多数程序员来说,机器的字节顺序是完全不可见的。但有时候,字节序会成为问题,特别是在不同类型的机器间传送数据时。比如小端法机器产生的数据发送到大端法机器时,字节就会成为反序。所以制定了网络字节序标准,网络字节序是大端法。在进行网络编程时,要确保数据在进行发送时需要转换为网络序,接受方再转换为自己的内部表示。这个过程涉及到六个函数:

#include<sys/types.h>
#include<netinet/in.h>

uint16_t htons(uint16_t hostshort);
uint16_t ntohs(uint16_t netshort);

uint32_t htonl(uint32_t hostint);
uint32_t ntohl(uint32_t netint);

/* 一些系统并没有提供下面两个函数,需要自己实现 */
uint64_t htonll(uint64_t hostlong);
uint64_t ntohll(uint64_t netlong);
符:处理器体系 (摘自维基百科
  • 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的字节序是可配置的。

计算机中的大端法和小端法》上有7条评论

  1. Pingback引用通告: 多平台兼容时字符编码问题 | 杨海坡的网志

    1. 海洋 文章作者

      那个 union + define 的作用就是把字节序变成了一个常量,l 表示 Little endian, b 表示 Big endian, 巧妙之处就是避免了调用函数的开销。:-)

      回复
  2. 冷若

    你好,我也是npuer,现在大三,四院。从你在ol上发表腾讯实习的文章的时候就开始关注你了,今年腾讯暑期实习快开始了,想请问一下,腾讯面试的时候会不会很看重专业,是不是会更关注计算机和数学专业的学生。非常希望能回复一下,还有很多问题想请教,可以回邮件,yclichuyang#qq.com,谢谢!

    回复
    1. 海洋 文章作者

      专业不是很看重,我认识的除了计算机学院,理学院、软件学院的外还有自动化学院、电子信息学院的等,腾讯笔试面试比较看重基础知识和综合素质,还有发展的潜力等。
      呵呵,一年的时间过的真快,祝你好运。

      回复

发表评论

电子邮件地址不会被公开。 必填项已用*标注