`
zhaohaolin
  • 浏览: 1016334 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

高位字节优先 低位字节优先

 
阅读更多

自第一台计算机诞生,其最小存储单元就被永久的定格了——一个由8个比特(bit)组成的称为字节(byte)的单位。计算机的所有内存以字节数组的方式进行编址。
当一个逻辑上长于一个字节的整形数据放置在内存中时(比如16位,32位,和64位的整数),计算机设计者需要考虑这些字节的存储顺序。一些体系结构的设计者选择了将字节的逻辑顺序与物理顺序一致,即将逻辑上较低的字节放置在物理上较低的字节上;另外一些设计者则选择了将字节的逻辑顺序与物理顺序相反,即将逻辑上较低的字节放置在物理上较高的字节上。前者被称为“little endian”,比如Intel x86系列;后者则被称为“big endian”,比如Motorola的PowerPC以及Sun Sparc。还有一些平台同时支持两种方案,由开发者决定使用哪一种。
两种选择为底层开发者带来了一定的困扰。比如,两个字节顺序不一致的平台之间进行通信,或者在两个字节顺序不一致的平台之间移植系统。这都是跨平台的例子,对于这些情况,字节顺序的问题是不能回避的。对于仅仅在一种平台上进行开发的程序员而言,如果它能够避免强制类型转换(比如将字节数组强制转换为一个长整数),一贯的以逻辑顺序来操作大于一个字节的整数,应该可以回避这个问题。但由于C语言是一种非常灵活的语言,有时候通过强制类型转换可以让代码非常精简,甚至达到非常巧妙的效果,所以,要求C程序员完全回避这个问题,几乎是不现实的。
由于Little Endian提供了逻辑顺序与物理顺序的一致性,让编程者摆脱了不一致性所带来的困扰,C语言开发者可以无所顾忌的按照自己的意愿进行强制类型转换,所以现代体系结构几乎都支持Little Endian。但Big Endian也有其优点,尤其对于汇编程序员:他们对于任意长度的整数,总是可以通过判断Byte 0的bit-7来查看一个整数的正负;对于Little Endian则不得不首先知道当前整数的长度,然后查看最高byte的bit-7来判断其正负。对于这种情况,big endian的开发者可以写出非常高效的代码。
两派的支持者争论不休,正像他们所支持名词(big endian和little endian)的典故所讲述的那样:Little Endian和Big Endian这两个名词来源于Jonathan Swift的《格利佛游记》其中交战的两个派别无法就应该从哪一端--小端还是大端--打开一个半熟的鸡蛋达成一致。:)在那个时代,Swift是在讽刺英国和法国之间的持续冲突,Danny Cohen,一位网络协议的早期开创者,第一次使用这两个术语来指代字节顺序,后来这个术语被广泛接纳了(摘自《深入理解计算机系统》)。
需要特别指出的是,通常所提到的Little Endian和Big Endian仅仅指字节顺序。在硬件设计者的术语中,对于一个字节内部的bit顺序也分Little Endian和Big Endian,但对于程序员而言,这些bit顺序的不同是透明的,也就是说,程序员只需要按照逻辑顺序来看待和操作字节内部的bit即可。
Endian的不同不仅仅带来字节顺序的不同,还有更多的问题。如果C程序员在定义一个结构体时,使用了bitwise的域定义,比如:
struct foo {
 int  a:3;
 int b:7;
 int c:13;
 int d:9;
};
这个结构体的一个对象会占用4个字节。由于a,b,c,d的类型都是int,所以他们都在以int32为单位的整数上分配bit,另外,由于他们的bit数量正好等于int32的bit数,所以,它们都分配于一个int所占用的空间。关键问题在于这些字节在这4个字节内是分配顺序是怎么样的?
对于little endian,其分配顺序与逻辑顺序是一致的,即在byte[0]的bit[0~2]上分配a,在byte[0]的bit[3,7]以及byte[1]的bit[0,1]上分配b,依次类推。
对于big endian,其方案会带来很大的问题。其分配顺序为:
字节物理顺序:从低到高;
字节内bit顺序:从高到底;
也就是说,big endian在bitwise的分配方案上,从字节顺序到bit顺序都反过来了(因为其正向存储顺序为:字节从高到底,bit从低到高(从程序员的观点看))。换句话说:big endian的bit分配顺序为,按照bit的逻辑顺序,从高到底进行分配。
          
                     |--------|--------|--------|--------|
Logical Byte Order   | byte 3 | byte 2 | byte 1 | byte 0 |
                     |--------|--------|--------|--------|
Bitwise allocation   |-a-|---b---|------c------|----d----|
请注意,并不是硬件平台使用的这种方案,而是C语言编译器。这是一种荒谬的方案,我想可能是C语言编译器的早期开发者希望通过编译器屏蔽掉big endian和little endian在bitwise allocation上的差异,而都与物理存储顺序一致。但由于其采用了bit order的反向分配,反而加剧了这种差异,随后的编译器为了保持兼容,也只好将错误延续了下来。
基于这种原因,在C语言中直接使用bitwise的方式定义结构体是一种危险的方式,因为这些代码是平台依赖的。当进行跨平台移植的时候必须重新定义这些结构体。
有两种方式可以消除这种风险:
1、使用逻辑移位的方式来操作bit;以上面的例子为例,我们可以这么做:
struct foo {
 int value;
};
#define SET_A(f,a)  do { (f) |= ((a)&0x7); } while(0)
#define SET_B(f,b)  do { (f) |= (((b)&0x7F)<<3); } while(0)
#define SET_C(f,c)  do { (f) |= (((c)&0x1FFF)<<10); } while(0)
#define SET_D(f,d)  do { (f) |= (((d)&0x1FF)<<23); } while(0)
#define GET_A(f)  ((f)&0x7)
#define GET_B(f)  (((f)>>3)&0x7F)
#define GET_C(f)  (((f)>>10)&0x1FFF)
#define GET_D(f)  (((f)>>23)&0x1FF)
2、对于big endian,我们可以使用相反的顺序来声明bitwise fields。仍然以上例为例:
#if LITTLE_ENDIAN
#define BITWISE(type,a,b,c,d)  type a, b, c, d
#else
#define BITWISE(type,a,b,c,d)  type d, c, b, a
#endif
struct foo {
 BITWISE(int, a:3, b:7, c:13, d:9);
};
对于little endian,逻辑顺序与物理顺序一致,只需要按照原样定义;而对于big endian,由于其整体的bit顺序恰好与逻辑顺序是相反的,所以,我们将顺序反过来,使其bit的分配顺序与逻辑顺序一致即可。
 

分享到:
评论

相关推荐

    S7-200SMART PLC中如何交换一个字WORD的高低字节?.docx

    执行SWAP指令后,VW50的新值会变成3412H,高位字节变为原来的低位字节,低位字节变为原来的高位字节。 **3. DWORD的字节交换** 对于32位数据(一个双字,即DWORD),如果需要交换高低字,可以直接使用MOV指令。在S7...

    CRC校验,高位在前,低位在后.zip

    在“CRC校验,高位在前,低位在后.zip”文件中,提供的CRC16校验方法遵循了一种特殊的位序规则,即校验码的高位在前,低位在后。 CRC16校验通常涉及以下步骤: 1. **初始化**: 在开始计算之前,CRC寄存器(可以...

    一个字拆分成高低字节;;

    在ST中,可以使用位操作函数(如SHL和 SHR)或者直接访问字的高位和低位字段。例如,可以用如下代码将一个字拆分为高低字节: ```structured_text VAR wordValue : Word; // 假设wordValue是我们要拆分的16位字 VAR...

    带CRC低字节在前 高字节在前、异或和、串口助手

    标题中的“带CRC低字节在前 高字节在前、异或和、串口助手”涉及到的是数据通信和校验技术,主要用于确保通过串行接口传输的数据的准确性和完整性。下面将详细解释这些概念及其重要性。 1. CRC校验:CRC(Cyclic ...

    汉字的机内码是指在计算机中表示一个汉字的编码.pdf

    为了避免机内码与ASCII码的冲突,通常会在区码和位码的基础上加上20H,然后再加80H,形成高位字节和低位字节。这样,每个汉字需要两个字节来表示,分别是高位字节和低位字节。高位字节的计算公式为:区码+20H+80H...

    浅学字节序——字节序大小端,主机字节序,网络字节序的理解

    在大端字节序中,数据的高位字节被存放在内存的低地址端,而低位字节被存放在内存的高地址端。例如,一个32位的数据0x12345678,在大端字节序中将被存储为:内存地址0x0000处存储0x12,内存地址0x0001处存储0x34,...

    S7-200SMART任意连续字节的数据高低字节调换的具体方法汇总.docx

    在16位或32位的数据中,高字节通常包含数值的高位部分,而低字节包含低位部分。例如,如果一个16位整数1234H在小端序中存储,它会被分为低字节4H和高字节12H。如果系统需要大端序,我们就需要将这两个字节互换。 在...

    TIA博途-32位浮点数大小端存储-高低字节转换的具体方法示例(4种字节排列顺序).docx

    `Float_in`接收32位浮点数,`Mode`变量用于切换字节顺序,而`HighByte`和`LowByte`分别输出高位和低位字节。 在模式0下,FB块按照大端字节序处理输入,所以当`Float_in`赋值为16#11223344时,输出变量的值为16#...

    本地字节序和网络字节序.pdf

    1. **小端字节序(Little Endian)**:在小端模式下,低位字节存储在内存的低地址处,高位字节则存储在高地址处。例如,在小端模式下,十六进制数`0x12345678`会被存储为`78 56 34 12`。Intel x86架构的CPU采用的...

    易语言低位高位模块

    "易语言低位高位模块"是易语言编程中一个重要的工具,用于处理数值的高低位部分,这对于理解和操作二进制数据尤其关键。 在计算机科学中,尤其是低级别的编程或硬件交互时,我们经常需要处理二进制数据的高位和低位...

    单精度浮点数与四字节十六进制数据的转换(左低右高)

    如果这四个十六进制数代表一个单精度浮点数,那么需要按照特定的顺序(通常是从左到右,即高位字节在前,低位字节在后,也称为大端序或网络序)重新组合成32位的二进制数。然后,根据IEEE 754的规则,解析这32位二...

    网络字节序和主机字节序

    Big Endian 是最直观的字节序,因为它按照通常的高位到低位的顺序写出值,并且按照内存地址从左到右按照由低到高的顺序写出。 在计算机中,字节序的选择取决于 CPU 的类型和操作系统。不同的 CPU 和操作系统可能...

    高低字节转换工具VB

    高低字节转换工具主要功能是在发送数据时将整数值按照特定规则转换为高位字节和低位字节,以便于通过串行通信等接口传输。这个过程通常涉及到将整数转换为二进制表示,然后进一步分割为高位和低位两个部分。 #### ...

    高低字节转换示例Demo

    大端模式下,最高有效字节(高位字节)位于内存的较低地址,而小端模式则相反,最低有效字节在前。例如,数值0x1234在大端模式下存储为`12 34`,而在小端模式下为`34 12`。高低字节转换就是在这两种模式之间转换,以...

    汉字转GB码

    GB2312编码是双字节编码系统,每个汉字由两个字节表示,第一个字节称为高位字节,第二个字节称为低位字节。高位字节范围通常在161(0xA1)到254(0xFE),低位字节在161(0xA1)到254(0xFE)。这种编码方式使得每个...

    linux 中socket编程 常用结构体 详解

    Internet 上数据以高位字节优先顺序在网络上传输,所以对于在内部是以低位字节优先方式存储数据的机器,在 Internet 上传输数据时就需要进行转换。 第一个结构类型是 struct sockaddr,该类型是用来保存 Socket ...

    Motorola格式编码1

    对于数据长度不超过8位的信号,按照Motorola格式,它们会完全包含在一个字节内,高位在高位字节,低位在低位字节。例如,一个4位的信号,其S_msb是最高两位,S_lsb是最低两位。这种布局使得数据读取更为直观,因为...

    易语言整数到字节数组

    例如,一个32位的整数在内存中占据4个字节,从高位到低位分别是最高有效位(MSB)到最低有效位(LSB)。转换时,我们需要把这4个字节分别提取出来,放入一个包含4个元素的字节数组中。 "整数到字节数组源码"描述的...

    字节的高低位知识.txt

    - **大端模式**:高位字节存储在内存的低地址处,低位字节存储在内存的高地址处。 - **小端模式**:低位字节存储在内存的低地址处,高位字节存储在内存的高地址处。 例如,在UTF-8编码中,如果遇到`FEFF`或`FFFE`...

    C语言编写modbus协议[参考].pdf

    5. 将crc值拆分为高位字节和低位字节,并将其与crc高位字节值表和crc低位字节值表进行比较,以确定crc值是否正确。 在C语言中编写Modbus协议需要了解Modbus协议的基本原理和通信机制,并且需要使用crc16算法来确保...

Global site tag (gtag.js) - Google Analytics