128-字节序

是不是感觉很突兀,前面的博文还有讲异步 IO 来着。从现在开始,我们将步入网络编程的轨道了。但是又怕初学者难以适应(我也是初学者^_^),所以不能大张旗鼓的喊着,网络编程开始啦……另一方面,apue 这本书讲的网络编程只是一个入门,真正想学习网络编程基础的话,还需要去看 《Unix 网络编程》这本书,简称 unp。当然这本书的学习笔记也是在计划内的啦。不过在此之前,我们先简单的学习下一些基本的网络知识吧。

1. 字节序

这个东西要讲清楚不容易,先来看图 1.


这里写图片描述
图1 内存中的数据

假设图 1 中在内存 0x1000 到 0x1003 这连续的 4 个字节保存了数据,这段数据对应的数据类型是 int 类型。我们知道 int 类型的数据在大多数编译器实现中都是 4 字节。

那么图 1 中这个 int 类型数据,到底是 0x10203040 还是 0x40302010?实际上这是依赖于处理器架构的。

对于 little-endian (小端)机器来说,这 4 字节数据被解释成 int 类型的话它就是 0x10203040,对于 big-endian (大端)机器来说,它被解释成 0x40302010.

小端的意思就是说,数据的低位(低字节)保存在内存的低地址部分,数据的高位(高字节)保存在内存的高地址部分。按照这个规则,对于小端机器来说,高地址 0x1003 这个位置保存的是数据最高位,0x1000 这个地址保存的是数据的最低位,所以最终的 int 类型数据就是 0x10203040.

大部分情况下,我们的使用都是小端机器,Intel 处理器和 AMD 处理器基本上都是小端的。但是也有一些处理器是大端的。

2. 网络字节序

为了能让不同处理器架构的机器进行通信,他们都需要将本机上的字节序转换成网络字节序,这样就解决了不同处理器之间的矛盾。

一般来说,网络字节序和大端机器上的字节序是一样的。

POSIX 提供了 4 个函数(也可能是用宏来实现的),可以让本机字节序和网络字节序之间进行互转。它们分别是:

#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);

其中,函数名字中的 h 表示 host(本机),n 表示 network(网络),而 l 表示要转换的数据是 4 字节,s 表示要转换的数据是 2 字节。

我们可通过实验来验证自己的机器是大端和小端的,另外网络字节序又是什么样的。

3. 实验

程序 btod.c 打印整型数据 0x10203040 在内存中的样子,然后将其转换成网络字节序后,再打印其在内存中的样子。

  • 代码
#include <stdio.h>
#include <arpa/inet.h>

union Int {
  char data[4];
  int x;
};

int main() {
  int i;
  union Int a;
  union Int b;
  a.x = 0x10203040;
  b.x = htonl(a.x);

  printf("a = 0x%08x\n", a.x);
  for (i = 0; i < 4; ++i) {
    printf("[%p]: %02x\n", a.data + i, a.data[i]);
  }

  puts("");

  printf("b = 0x%08x\n", b.x);
  for (i = 0; i < 4; ++i) {
    printf("[%p]: %02x\n", b.data + i, b.data[i]);
  }

  return 0;
}
  • 编译和运行
$ gcc btod.c -o btod
$ ./btod


这里写图片描述
图1 运行结果

从图 1 中可以看到,0x10203040 在内存中的样子,低地址保存的是数据低字节,即 0x40,而高地址保存的是数据的高字节,即 0x10.

当我们将 0x10203040 转换成网络字节序后,在内存中的样子就完全相反了。

4. 总结

  • 掌握小端和大端的区别
  • 知道什么是字节序
  • 为什么会出现网络字节序
<think>嗯,用户想要用易语言实现三字节和二字节的解码算法,还提到了具体公式。首先,我需要理解用户提到的算法是什么样的。用户提供的引用里有一个字节集中间处理的例子,看起来是截取中间部分的数据,可能涉及到动态加密或者数据解码。 用户的问题是关于解码算法的,所以可能需要从字节集中提取特定长度的数据,并根据某种公式转换。三字节和二字节解码可能涉及到将多个字节组合成一个数值,或者进行某种编码转换,比如Base64或其他自定义编码。 首先,我需要确认常见的解码场景。比如,Base64编码通常将3个字节编码成4个字符,解码时反过来。但用户提到的是三字节和二字节,可能不是Base64。或者可能是用户自定义的算法,将3个字节的数据转换为2个字节,或者相反。 假设用户需要将3个字节的数据解码为2个字节,或者反之,可能需要处理字节的拆分和组合。例如,每个三字节组可能代表两个12位的值,组合成两个16位(两字节)的数值。或者,可能涉及到位移操作,比如将三个字节的高位和低位分开,重新组合成两个字节。 根据用户提供的引用,易语言中的字节集操作函数包括取字节集中间、取字节集长度等。所以,解码过程可能需要遍历字节集,每次取3个或2个字节进行处理,然后合并结果。 例如,三字节解码为二字节的情况:假设三个字节的数据,每三个字节转换为两个字节。可能的步骤是将三个字节拆分为两个12位的数,然后每个12位数存储为两个字节(16位)。或者,使用某种位移运算,比如将前两个字节的高位和第三个字节的低位组合。 例如,具体公式可能是这样的: - 对于三字节到两字节,比如第一个字节左移4位加上第二个字节右移4位,得到第一个两字节;第二个字节的低4位左移8位加上第三个字节,得到第二个两字节。但这只是假设,需要用户提供具体公式。 但用户没有给出具体公式,所以可能需要举一个例子,说明如何通过位移和位运算来实现三字节和二字节之间的转换。例如,一个常见的例子是Base64编码,但可能用户需要的是其他方式。 另外,用户提供的引用中的代码是截取字节集中间的一部分,可能涉及到去除头部和尾部的数据,比如去掉前5个字节和后10个字节,然后处理中间部分。这可能是在处理特定格式的数据包或加密后的数据,需要先截取有效部分再进行解码。 因此,可能的实现步骤是: 1. 读取字节集数据,并截取有效部分(如用户引用中的操作)。 2. 遍历处理每个三字节或两字节的块。 3. 对每个块应用解码算法,比如位移和位或操作,转换为目标字节数。 4. 将处理后的字节集返回。 例如,假设三字节解码为两字节的算法是: - 第一个两字节由第一个字节左移4位加上第二个字节右移4位。 - 第二个两字节由 (第二个字节与0x0F) 左移8位加上第三个字节。 但这需要具体公式,如果用户没有提供,可能需要给出一个通用的示例,说明如何操作字节。 在易语言中,处理字节集可以使用“取字节集数据”命令,结合指针操作,或者使用循环逐个处理字节。例如: 1. 使用取字节集长度获取数据长度。 2. 循环处理每个块,每次取3个字节。 3. 对这三个字节进行位运算,拆分为两个两字节的数据。 4. 将结果添加到新的字节集中。 或者,如果是两字节解码为三字节,则反过来。 由于用户没有给出具体公式,可能需要给出一个示例,假设一个常见的场景,比如将3个8位字节转换为2个12位的值,存储为两个16位整数(两字节),但需要考虑字节序。 例如,三个字节B1, B2, B3,转换为两个12位的值: - 第一个值: (B1 << 4) | (B2 >> 4) - 第二个值: ((B2 & 0x0F) << 8) | B3 然后将这两个12位值存储为两个16位的整数,每个占两个字节。但易语言中的数值存储需要考虑高低字节顺序,比如使用“到字节集”函数时,短整数型是低位在前高位在后。 因此,代码示例可能如下: 处理三字节到两字节: .版本 2 .子程序 三转二解码, 字节集 .参数 输入数据, 字节集 .局部变量 输出数据, 字节集 .局部变量 i, 整数型 .局部变量 B1, 字节型 .局部变量 B2, 字节型 .局部变量 B3, 字节型 .局部变量 值1, 短整数型 .局部变量 值2, 短整数型 输出数据 = { } .计次循环首 (取字节集长度 (输入数据) ÷ 3, i) B1 = 取字节集数据 (输入数据, #字节型, (i - 1) × 3 + 1) B2 = 取字节集数据 (输入数据, #字节型, (i - 1) × 3 + 2) B3 = 取字节集数据 (输入数据, #字节型, (i - 1) × 3 + 3) 值1 = 左移 (B1, 4) ∨ 右移 (B2, 4) 值2 = 左移 (位与 (B2, 15), 8) ∨ B3 输出数据 = 输出数据 + 到字节集 (值1) + 到字节集 (值2) .计次循环尾 () 返回 输出数据 但需要注意易语言中的位操作函数是否正确,比如是否有左移、右移命令,或者需要使用位与、位或。此外,到字节集可能会将短整数型转换为两个字节,但需要考虑字节顺序。 同样,二字节到三字节的解码可能需要反向操作。 可能还需要处理数据长度不是3的倍数的情况,比如补零或者截断,但用户可能希望有具体的处理方式,这里可能需要用户进一步说明。 最后,根据用户提供的引用,可能需要在处理前截取字节集中间的一部分,如: 字节集数据中间 = 取字节集中间 (原始数据, 6, 取字节集长度 (原始数据) - 10) 然后在处理时使用这个中间数据。 综上,给出一个示例代码,说明如何实现三字节到两字节和二字节到三字节的解码,假设具体的位移和组合方式,并提醒用户根据实际算法调整位操作部分。</think>### 易语言三字节/二字节解码算法实现示例 #### 1. 三字节转两字节解码 假设算法规则为:每3字节数据通过位运算拆解为2个12位数值,存储为两个16位(2字节)短整数。 ```easy-language .版本 2 .子程序 三字节解码, 字节集 .参数 输入数据, 字节集 .局部变量 输出数据, 字节集 .局部变量 i, 整数型 .局部变量 B1, 字节型 .局部变量 B2, 字节型 .局部变量 B3, 字节型 .局部变量 值1, 短整数型 .局部变量 值2, 短整数型 输出数据 = { } .计次循环首 (取字节集长度 (输入数据) ÷ 3, i) ' 取三个连续字节 B1 = 取字节集数据 (输入数据, #字节型, (i - 1) × 3 + 1) B2 = 取字节集数据 (输入数据, #字节型, (i - 1) × 3 + 2) B3 = 取字节集数据 (输入数据, #字节型, (i - 1) × 3 + 3) ' 解码公式实现 值1 = 左移 (B1, 4) + 右移 (B2, 4) ' 高8位 = B1左移4位 | B2高4位 值2 = 左移 (位与 (B2, 15), 8) + B3 ' 低8位 = B2低4位左移8位 | B3 输出数据 = 输出数据 + 到字节集 (值1) + 到字节集 (值2) .计次循环尾 () 返回 输出数据 ``` #### 2. 二字节转三字节解码 逆向操作时,将两个16位数值还原为3个原始字节: ```easy-language .子程序 二字节解码, 字节集 .参数 输入数据, 字节集 .局部变量 输出数据, 字节集 .局部变量 i, 整数型 .局部变量 值1, 短整数型 .局部变量 值2, 短整数型 .局部变量 B1, 字节型 .局部变量 B2, 字节型 .局部变量 B3, 字节型 输出数据 = { } .计次循环首 (取字节集长度 (输入数据) ÷ 4, i) ' 每4字节包含2个短整数 ' 读取两个短整数 值1 = 取字节集数据 (输入数据, #短整数型, (i - 1) × 4 + 1) 值2 = 取字节集数据 (输入数据, #短整数型, (i - 1) × 4 + 3) ' 编码还原公式 B1 = 右移 (值1, 4) ' 取高8位的前4位 B2 = 左移 (位与 (值1, 15), 4) + 右移 (值2, 8) ' 组合中间4位 B3 = 位与 (值2, 255) ' 取低8位 输出数据 = 输出数据 + 到字节集 (B1) + 到字节集 (B2) + 到字节集 (B3) .计次循环尾 () 返回 输出数据 ``` #### 3. 动态截取中间数据 根据引用内容,可先截取有效数据段: ```easy-language 字节集数据中间 = 取字节集中间 (原始数据, 6, 取字节集长度 (原始数据) - 10) ' 移除头尾特定字节[^1] 解码结果 = 三字节解码 (字节集数据中间) ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值