今天这篇文章,想跟大家分享一个计算机科学(PLC编程)的基础知识:即数据在内存中的存放序列(字节序)的问题。没看明白?详细说明下:我们知道,“位”(bit)是计算机数据存储的最小单位,八个“位”组成一个字节(Byte),两个字节组成一个“字”(Word),其中一个字节为该“字”的低字节,另一个字节为该“字”的高字节。
好了,现在问题来了:当我们把一个整数(比如十六进制数:0x0384)存放到一个“字”里的时候,可以有两种存放方法:一种方法可以把“0x03”存放到低字节,把“0x84”存放到高字节;另一种方法正好相反:可以把“0x03”存放到高字节,把“0x84”存放到低字节。
应该使用哪种存放方式呢?这个问题,曾经在计算机科学界引起巨大的争论。1980年,英国计算机科学家丹尼·科恩(Danny Cohen)发表了一篇题为“在圣战中祈求和平(On Holy Wars and a Plea for Peace)”(注:北岛李工译)的论文。丹尼·科恩在论文中引述了英国作家乔纳森·斯威夫特(Jonathan Swift)于1726出版的一部长篇讽刺小说:格列佛游记(Gulliver's Travels)中的一个故事。故事中小人国的臣民为水煮蛋应该是从大的一端(Big-End)剥开还是小的一端(Little-End)剥开而争论不休。主张从大的一端(Big-End)把水煮蛋剥开的人被称为Big-Endian(大端),主张从小的一端(Little-End)把水煮蛋剥开的人被称为Little-Endian(小端)。
丹尼·科恩在论文中用这个故事进行类比,并提出了最高权重位(Most Significant Bit,MSB)和最低权重位(Least Significant Bit,LSB)的概念。
所谓“最高权重位(MSB)”,是指二进制数制中,位数最大的位。所谓“最低权重位(LSB)”,是指二进制数制中,位数最小的位。比如二进制数:1101,最左边的“1”,能代表“2”的“3”次方;从左数第二个“1”,能代表“2”的“2”次方;而最右边的“1”,代表“2”的“0”次方。可见最左边的“1”权重最高,所以该位就是“最高权重位(MSB)”,最右边的“1”权重最低,所以该位就是“最低权重位(LSB)”。
把“最高权重位(MSB)”存放到低字节,把“最低权重位(LSB)”存放到高字节,这种字节序,称为“大端(Big-Endian)”字节序;相反,把“最低权重位(LSB)”存放到低字节,把“最高权重位(MSB)”存放到高字节,这种字节序,称为“小端(Little-Endian)”字节序。
比如:要把十六进制数0x01020304,存放到起始地址为0x100的地方。按照大端(Big-Endina)字节序存放的方式,会把0x01存放到起始地址0x100中,把0x04存放到地址0x103中;而如果按照小端(Little-Endian)字节序方式存放,会把0x01存放到地址0x103中,把0x04存放到地址0x100中,如下图:
英特尔X86的微处理器使用的小端(Little-Endian)字节序,ARM系列单片机使用的是大端(Big-Endian)字节序。西门子S7系列PLC使用大端(Big-Endian)存放方式,比如:给DB801.DBW510赋值W#16#0384(即:0x0384),在线监控发现DB801.DBB510的值为0x03,DB801.DBB511的值为0x84,可见存放方式为大端(Big-Endian)字节序。
网络传输也存在字节序的问题,以太网使用大端(big-endian)字节序,串口通信(RS232)使用小端(little-endian)字节序。
好了,关于字节序就先聊到这里了。另外关于丹尼·科恩(Danny Cohen)那篇著名的论文,我Google到了英文原著,会稍加排版,放到官网本文的末尾,感兴趣的可以下载来看看。
相关参考文章:
发表评论