字节序—字节内部的位序

2023-05-16

Big endian machine: It thinks the first byte it reads is the biggest.

Little endian machine: It thinks the first byte it reads is the littlest.


这是linux对IP头的定义 /usr/include/linux/ip.h 或 linux/include/linux/ip.h)

  1. struct iphdr { 
  2. #if __BYTE_ORDER == __LITTLE_ENDIAN 
  3. uint8_t ihl:4, 
  4. version:4; 
  5. #elif __BYTE_ORDER == __BIG_ENDIAN 
  6. uint8_t version:4, 
  7. ihl:4; 
  8. #endif 
  9. uint8_t tos; 
  10. uint16_t tot_len; 
  11. uint16_t id; 
  12. uint16_t frag_off; 
  13. uint8_t ttl; 
  14. uint8_t protocol; 
  15. uint16_t check; 
  16. uint32_t saddr; 
  17. uint32_t daddr; 
  18. /*The options start here. */ 
  19. }; 

版本号和首部长度是同一个字节的,这也要区分大端小端吗?我一直以为大端小端是字节间顺序的问题,不是字节内部位顺序的问题。网络数据发送时是字节流还是位流?发送时uint16_t和uint32_t的高字节必需先发送,那么同一字节的高位先发送还是低位?我找不到gcc讲结构位定义的文档,有链接么?

可以这样来解释,
1)从道理上来说,little endian中的位应该这样排列:
01234567
即排在前面的是低位。因此,先分配least significant bits
2)而在Big endian中,位应该这样排列:
76543210
即排在前面的是高位。因此,先分配most significant bits。

可以这样来理解,
1)在Big Endian的情况下,"排在前面的是高位"
a. 对于顺序的两个字节来说,第一个字节是高位(排在前面),第二个字节是低位(排在后面)。
b. 对于字节内部的位来说,
-------most significant bits排在前面,是高位,
-------least significant bits排在后面,是低位。
2)在Little Endian的情况下,"排在前面的是低位"
a. 对于顺序的两个字节来说,第一个字节是低位(排在前面),第二个字节是高位(排在后面)。
b. 对于字节内部的位来说,
-------least significant bits排在前面,是低位,
-------most significant bits排在后面,是高位。

这样,在对struct中的成员进行分配的时候,"按排列顺序分配,先分配排在前面的"
1)big endian从高位向低位分配,
a. 对字节,是先分配低地址的字节,再分配高地址的字节。
b. 对位域,先分配most significant bits,再分配least significant bits。
1)little endian从低位向高位分配,
a. 对字节,是先分配低地址的字节,再分配高地址的字节。
b. 对位域,先分配least significant bits,再分配most significant bits。

======================================

以上说的都是分配的顺序。

对于IP协议来说,
1)IP's byte order is big endian.
2)The bit endianness of IP inherits that of the CPU,
3)and the NIC takes care of converting it from/to the bit transmission/reception order on the wire.

并且,按照IP协议,
1)"version" is the most significant four bits of the first byte of an IP header.
2)"ihl" is the least significant four bits of the first byte of the IP header.

也就是说,version必须分配在most significant four bits,
按照上面说的分配顺序,在big endian中,version必须放在前面。

 

MSB  most significant bits

LSB    least significant bits

一句话:对于 little-endian 来说 MSB 在高地址,对 big-endian 来说 MSB 在低地址。

 

Here is how we would write the integer 0x0a0b0c0d for both big endian and little endian systems, according to the rule above:
Write Integer for Big Endian System
byte addr 0                1              2               3
bit offset  01234567 01234567 01234567 01234567
binary      00001010 00001011 00001100 00001101
hex           0a          0b         0c         0d

Write Integer for Little Endian System
byte addr 3               2              1                0
bit offset 76543210 76543210 76543210 76543210
binary     00001010 00001011 00001100 00001101
hex          0a           0b        0c          0d
In both cases above, we can read from left to right and the number is 0x0a0b0c0d.

 

在小字节序机器上跑测试例1:

  1. int value = 0x12345678;
  2.         union ValueT
  3.         {
  4.             int value;
  5.             char data[4];
  6.         } a;
  7.         a.value = 0x12345678;
  8.         printf("value is 0x%x\n", a.value);
  9.         printf("address is %p, 0x%x\n",&a.data[0], a.data[0]);
  10.         printf("address is %p, 0x%x\n",&a.data[1], a.data[1]);
  11.         printf("address is %p, 0x%x\n",&a.data[2],  a.data[2]);
  12.         printf("address is %p, 0x%x\n",&a.data[3], a.data[3]);
  13.         //value is 0x12345678
  14.         //address is 0012FF6C, 0x78
  15.         //address is 0012FF6D, 0x56
  16.         //address is 0012FF6E, 0x34
  17.         //address is 0012FF6F, 0x12

测试例2:

  1. struct bitfield{ 
  2.             int ia:2; 
  3.             int ib:6; 
  4.         } field; 
  5.         field.ia=1; 
  6.         field.ib=4; 
  7.         char * c; 
  8.         c=(char *)&field; 
  9.         printf("%d\n",*c);
  10.         // 17 = 000100 01

原帖地址:http://www.unixresources.net/linux/clf/program/archive/00/00/64/28/642822.html

亦可参考:http://bbs.chinaunix.net/viewthread.php?tid=823662&extra=&page=1    

               http://www.unixresources.net/linux/clf/linuxK/archive/00/00/63/86/638637.html

 

Endianness of CPU
The CPU endianness is the byte and bit order in which it interprets multi-byte integers from on-chip registers, local bus, in-line cache, memory and so on. 

Little endian CPUs include Intel and DEC. Big endian CPUs include Motorola 680x0, Sun Sparc and IBM (e.g., PowerPC). MIPs and ARM can be configured either way.

Endianness of Ethernet
Ethernet is big endian. This means the most significant byte of an integer field is placed at a lower wire byte address and transmitted/received in front of the least significant byte.

Endianness of IP
IP's byte order also is big endian. The bit endianness of IP inherits that of the CPU, and the NIC takes care of converting it from/to the bit transmission/reception order on the wire.


小端系统中的比特顺序和字节顺序


这次总算有原创的文章了,因为工作中比特顺序/字节顺序总是搞不清楚。正好昨天晚上和同事好好考论了一番,在这里总结一下。

1. 小端

在bitstream的定义中,经常见到这样的定义

exam{
A:18 bit stream left bit first
B: 14 bit stream left bit first
}

在小端(little endian)系统中,上述32bit被读入内存,memory map如下
------------------------------------------------------------------------------------
| A7 ... A0 | A15 ... A8 | B5 ... B0 A17 A16 | B13 ... B6 |
 

    byte0              byte1                      byte2                    byte3

low address --------------------------------> highaddress
-------------------------------------------------------------------------------------
NOTE:该处A0代表线路上最先到达的bit,A17代表最后到达.

可见小端系统是一个移位性质的寄存器,先到达的bit放在byte内的高位地址。(所谓小端地址的定义是:most significantbyte in high address。所以 0x01 0x02 0x030x04,代表的数据是0x04030201.同样的道理,在字节内部,物理地址高的bit代表高位。所以如果一个binarystream在字节中从左到右的顺序是 10001010,那么它代表的byte数据应该是0x51,而不是0x8A.)

可见,属于同一个域A的数据在物理地址上面并不连续了。为了处理这个问题,我们必须把这32bit数据变换为小端Byte顺序,既
------------------------------------------------------------------------------------
| B13 ... B6 | B5 ... B0 A17 A16 | A15 ... A8 | A7 ... A0 |
      byte3                    byte2                    byte1          byte0

low address --------------------------------> highaddress
-------------------------------------------------------------------------------------

这样一来,同一个域的数据在物理上就连续了。使用C语言bit field的定义
struct{
      UINT32 B:14;
      UINT32 A:18;
}
这样 B 对应了这个32bit结构的低14bits, A对应了高18bits。编译器只需要简单的截断移位就可以处理这两个域了。

2. 大端

大端系统正好相反,在byte顺序上是高位数据对应least significantbyte。在byte内部靠近高位地址的bit对应least significant bit.

数据到达内存的时候
------------------------------------------------------------------------------------
| A0 ... A7 | A8 ... A15 | A16 A17 B0 ... B5 | B6 ... B13 |
      byte0              byte1                      byte2                    byte3

low address --------------------------------> highaddress
-------------------------------------------------------------------------------------

大段在物理地址上和传输顺序(文档描述)一模一样,比较容易理解。这也是大端结构设计的初衷。

于是只需要在bit field声明如下结构:
struct{
      UINT32 A:18;
      UINT32 B:14;
}
这样就一目了然了。

3.总结

这些内容如果不是经常使用非常容易混淆,因为小端需要有两个转换,首先是byte顺序,其次是bit顺序。使用的时候最好在pc上多做实验。


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

字节序—字节内部的位序 的相关文章

随机推荐

  • Postman 汉化(Postman中文版)

    1 首先从官网下载postMan安装包 postman官网下载地址 Download Postman Get Started for Free 2 下载postMan 汉化包 app zip postman汉化包 Releases hlmd
  • UDP的客户端和服务器端的实例(VC6.0实现)

    服务器端程序 xff1a UdpServer cpp Defines the entry point for the console application include 34 stdafx h 34 include lt stdio h
  • STM32中关于串口中断的调试(不断进入发送中断的原因)

    说来惭愧 xff0c 前日在调试stm32f10系列的单片机的时候 xff0c 想做一个关于串口发送的状态机 xff0c 每隔100毫秒发送一次命令 没有用DMA xff0c 就是想单纯的使用发送中断来数据 xff0c 结果在调试的时候一直
  • Psoc Creator 入门——空工程的建立

    最近在做psoc 4000芯片的开发 xff0c 现在简单的说说怎么利用psoc creator进行开发 首先 xff0c 安装psoc creator xff0c 我使用的版本是4 0 安装过程省略 xff0c 赛普拉斯官网有下载链接 x
  • mbedtls使用openssl生成的自签名证书进行TLS实验

    目录 1 使用openssl生成自签名证书2 VS2013编译mbedtls3 mbdtls默认对证书的要求4 mbdtls测试例子详解5 运行测试程序 1 使用openssl生成自签名证书 openssl是一个安全套接字层密码库 xff0
  • IIC的通信波形分析

    关于IIC xff0c 不解释它的历史了 xff0c 有兴趣自己去百度看看 xff0c 本文的图片是由周立功的LAB6021逻辑分析仪抓取的 xff0c 通信的波形是抓取的cypress的psoc 4000芯片得到的 最近项目需要用到触摸I
  • linux下的CSV文件操作

    先介绍一下什么是csv文件 xff0c 这是一种简单的文本文件 xff0c 也被称为逗号分隔值文件 主要是用于存储简单的数据 xff0c 下面在weindows下用UE简单生成一下文件 然后用excel打开 这就是一个简单的csv文件 xf
  • GNU makefile入门——刚开坑,没有干货

    一个完整的makefile文件包含5个部分的内容 xff1a 显示规则 xff0c 隐含规则 xff0c 变量和指示符 xff0c 注释 显示规则 xff1a 包括目标 xff1a 依赖规则 命令 隐含规则 xff1a make根据目标文件
  • Renesas CS+ for ca cx入门(一)

    这是一篇关于Renesas的CS 43 for ca xff08 以下简称CA xff09 的入门简介 xff0c 在网上关于这个IDE的使用方法比较少人讲述 xff0c 兴许使用的人比较少吧 另一个类似的IDE是CS 43 for cc
  • 单片机——按键扫描

    按键扫描 xff0c 我想应该是比较简单的单片机应用了 xff0c 但是有时候看起来简单的东西反而不好写 本文拿大部分人觉得简单的按键扫描聊聊我工作至今对于软件结构的理解 嗯 xff0c 对的 xff0c 是结构 xff0c 不是架构 xf
  • keil的错误: Error: Encountered an improper argument 的解决方法

    将附件中的文件下载然后放到keil一下的安装目录中即可C Keil v5 UV4 xff0c 选择替换即可 文件链接 xff1a http download csdn net download ma57457 10118005 官方说的是支
  • 嵌入式软件没有层次感的原因

    因为软件是一个人写的 xff01 xff01 xff01
  • 博客网站转移

    我的博客会慢慢的转移到新的网站上 xff0c 新的地址为oopsrtos com xff0c 新博客会对arm 体系结果做更深入的探讨 xff0c 主要是关于实时操作系统内核开发的研究 最近在研究FPU xff0c 从内核层解释在操作系统中
  • keil工程中找不到头文件的可能原因

    今天用keil写一个串口调试程序 xff0c 编译工程时 xff0c 总是找不到type h头文件 xff0c 而该文件又是必须的 于是 xff0c 重新看设置 xff0c 头文件路径已经包含到工程里了 xff0c 头文件也已经添加到工程里
  • 在NAND FLASH上建立YAFFS2文件系统

    在NAND FLASH上建立YAFFS2文件系统 xff08 一 xff09 By on 2006 07 22 经过了半个多月的努力 xff0c 终于搞定nandflash的mtd驱动和上层的yaffs2文件系统 这半个多月来几乎每天都要和
  • 个人学习笔记-矩阵的四则运算

    目录 1 矩阵的四则运算1 1 矩阵的乘法运算1 2矩阵的加法运算1 3矩阵的减法运算 2 接口测试输出结果 1 矩阵的四则运算 1 1 矩阵的乘法运算 span class token comment 矩阵乘法 C语言实现分解步骤 xff
  • 单片机通信接口:UART、I2C、SPI、TTL、RS232、RS422、RS485、CAN、USB

    参考资料 xff1a 这些单片机接口 xff0c 一定要熟悉 xff1a UART I2C SPI TTL RS232 RS422 RS485 CAN USB SD卡 秒懂所有USB接口类型 xff0c USB接口大全 1 UART UAR
  • PCB中走线与电流的关系

    参考资料 xff1a 超强整理 xff01 PCB设计之电流与线宽有八种关系 1 前言 PCB的载流能力取决与以下因素 xff1a 线宽 线厚 xff08 铜箔厚度 xff09 容许温升 PCB走线越宽 xff0c 载流能力越大 但走线宽度
  • Visual Studio各版本集成的Visual C++版本对应关系

    Visual Studio版本集成的Visual C 43 43 版本对应关系如下 xff1a Visual Studio 6 xff1a vc6 Visual Studio 2003 xff1a vc7 Visual Studio 200
  • 字节序—字节内部的位序

    Big endian machine It thinks the first byte it reads is the biggest Little endian machine It thinks the first byte it re