大端与小端概念、多字节之间与单字节多部分的大小端转换详解

简介: 大端与小端概念、多字节之间与单字节多部分的大小端转换详解


前言

本文主要介绍三个内容:

  1. 大端与小端概念
  2. 多字节之间的大小端转换
  3. 单字节多部分的大小端

    定义TCP/IP协议结构体的时候,常常搞不清楚一字节分成多个部分时,大小端是如何转换的,今天特意写下来,以免过几天又搞不清楚了。

    字节是计算机的基本单位,8bit=1byte,八位一字节,如果存储一个数,大于一个字节,由于计算机内存排布的不同,就要区分字节顺序:大端-Big Endian(High-byte first) 和 小端-Litter Endian(Low-byte first)

  本专栏知识点是通过零声教育的线上课学习,进行梳理总结写下文章,对c/c++linux课程感兴趣的读者,可以点击链接 C/C++后台高级服务器课程介绍 详细查看课程的服务。

高字节、低字节

一个int类型的整数:123456789

  • 最左边的叫高字节,即 0x07
  • 最右边的叫低字节,即 0x15
进制
二进制 00000111 01011011 11001101 00010101
十六进制 07 5B CD 15

高地址、低地址

    在内存中,多字节对象都是被存储为连续的字节序列。例如在C语言中,一个类型为int的变量n,如果其存储的首个字节的地址为0x1000,那么剩余3个字节的地址将存储在0x1001~0x1003。总之,不管具体字节顺序是以什么方式排列,内存地址的分配一般是从小到大的增长。我们常把0x1000称为低地址端,把0x1003称为高地址端。

大端、小端

  • 大端:高字节存放在低地址,低字节存放在高地址(大端从左往右,很符合人的思维)
  • 小端:低字节存放在低地址,高字节存放在高地址(低放低,大端的逆序)

(123456789)10 = (07 5B CD 15)16 ,这个int整形4字节该如何存储呢

内存地址(低——>高) 字节存储顺序
大端(Big Endian) 0x1000 0x1001 0x1002 0x1003 0x07 0x5B 0xCD 0x15 高字节存放在低地址
低字节存放在高地址
小端(Litter Endian) 0x1000 0x1001 0x1002 0x1003 0x15 0xCD 0x5B 0x07 低字节存放在低地址
高字节存放在高地址

网络字节序和主机字节序

    网络字节序(Network Order):TCP/IP各层协议将字节序定义为大端(Big Endian),因此TCP/IP协议中使用的字节序通常称之为网络字节序。

    主机字节序(Host Order):整数在内存中保存的顺序,它遵循小端(Little Endian)规则(不一定,要看主机的CPU架构,不过大多数都是小端)。所以当两台主机之间要通过TCP/IP协议进行通信的时候就需要调用相应的函数进行主机序列(Little Endian)和网络序(Big Endian)的转换。

大小端转换用在什么地方

   从上面我们已经知道了,TCP/IP各层协议 一般都是大端 , 而我们常用的计算机,一般都是小端。

   所以如果我们要发送协议的时候,是要发送大端的;当我们接收到大端的协议,想要解析出来使用的时候,就要转成小端。

   再往小的看,我们转换,转换的是整数(short ,int ,uint等等),因为只有整数才会有多个字节,对于单字节的char来说,是不需要转换的(特殊情况见下)。

   如果是做跨平台开发时,双方需要协商好字节序,然后根据程序运行的环境,确定是否需要字节序转换。例如约定的通讯字节序为大端,默认的windows采用的小端,那收到数据后就需要做转换操作。

特殊情况:关注每个字节具体数值,单字节多部分的大小端转换

   关注某个字节的具体 bit 的时候,是需要考虑大小端的。我们上面所说的,都是多字节的情况,对于int来说,4字节,我们只关注字节与字节之间的顺序;而对于一个字节,并且我们把这8bit,分成多个部分的情况的时候,我们需要考虑 bit 与 bit 之间的顺序,是需要考虑大小端的。

   那么如何将大端的一字节的,转换成小端呢? 根据协议规定的字节内 每部分 的顺序,做 逆序 即可。

websocket协议

   举个例子,在websocket协议介绍与基于reactor模型的websocket服务器实现,里面,我们就根据websocket的协议,定义了结构体。

   在协议中,将一字节,分成了5个部分,我们常用的ntohs,ntohl都是针对多字节的,那么收到了这份协议,如何将这一字节的大端转换成小端呢?我们通过结构体来实现。当这一字节存入结构体内,我们通过下面的方法,变成小端。

typedef struct _ws_ophdr {
    unsigned char opcode: 4,
            rsv3: 1,
            rsv2: 1,
            rsv1: 1,
            fin: 1;
    unsigned char payload_len: 7,
            mask: 1;
} ws_ophdr;

ip协议

   在ip协议里面,我们观察到第一个字节中,version4个bit,hdrlen4个bit。但是这个大端,如果要转换成小端,就逆序即可。

struct iphdr {
    unsigned char hdrlen: 4,
            version: 4;
    unsigned char tos;
    unsigned short totlen;
    unsigned short id;
    unsigned short flag_offset;
    unsigned char ttl;
    unsigned char type;
    unsigned short check;
    unsigned int sip;
    unsigned int dip;
};

多字节之间 常用大小端转换api

  • 函数名的h表示主机host, n表示网络network, s表示short, l表示long;下面这几个函数, 如果本来不需要转换,函数内部就不会做转换。
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);

IP地址转换函数:

   p->表示点分十进制的字符串形式

   to->到

   n->表示network网络

  • 将字符串形式的点分十进制IP转换为大端模式的网络IP(整形4字节数)
int inet_pton(int af, const char *src, void *dst);

  • 网络IP转换为字符串形式的点分十进制的IP
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
目录
相关文章
|
6月前
|
存储
计算机存储,字节分为大端和小端
计算机存储,字节分为大端和小端
91 1
|
存储 C语言
大端存储和小端存储
1.大小端字节序 2.大端存储 3.小端存储 4.为什么会有大小端存储模式之分? 5.如何判断当前机器是大端存储还是小端存储 方法1 方法2
2984 0
|
2月前
|
Java
Byte 高位/低位简介绍(大端格式/小端格式)
Byte 高位/低位简介绍(大端格式/小端格式)
115 1
|
6月前
|
存储 小程序 编译器
什么是“大小端字节序”存储模式?
这篇内容讨论了计算机内存中存储整型变量的方式,特别是针对不同字节序(大端和小端)的概念。文章首先解释了正负整数在内存中以补码形式存储的规则,然后提出了一个问题:当一个4字节的整数在内存中存储时,其字节是如何分布的?接着,文章引入了大端字节序和小端字节序的概念,其中大端模式将高位字节存储在低地址,小端模式则相反。文章通过示例说明了两种存储模式的区别,并提供了一道题目来判断当前机器使用的字节序。最后,给出了一个简单的程序来检测系统是大端还是小端。
97 0
什么是“大小端字节序”存储模式?
|
存储 C语言 C++
C语言 “整型在内存的存储,大小端存储模式的介绍“
C语言 “整型在内存的存储,大小端存储模式的介绍“
55 1
|
存储
大端法与小段法的区别
大端法与小段法的区别
308 0
|
存储 小程序 编译器
C语言:大小端字节序存储
大端字节序存储模式:把一个数据低位字节处的数据存放在高地址处,数据高位字节处的数据存放在低地址处
106 0
|
存储 编译器 C语言
大小端字节序和整型提升
大小端字节序和整型提升
|
存储 小程序 编译器
大小端字节序详解
在开始正文之前,我想先问一下大家,内存中是怎样存放一个数的?当然啊,我这里问的不是数据存储的形式(比如整数存原码,负数存补码),而是一个数据存放的顺序 我们先看下面这个例子,当我们看看当把十六进制函数0x11223344存进内存中会是怎么样的。
大小端字节序详解