一字节内的位序(bit)大端小端分析

本文深入探讨了网络通信中位序(bit)的概念,解释了在网络传输中,尽管指令无法直接寻址到字节内的位,但位序在TCP/IP通信中依然存在并发挥作用。文章指出,网络通信中位序的处理对应用层开发者是透明的,由网卡自动进行小端位序的转换,确保数据在不同字节序的主机间正确传输。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

   相信字节序、大端、小端的概念相关资料很多,大家都比较清楚了。这里说明下一字节内部位序(bit)的概念。

   在计算机中底层一个存储单元是字节,因此你的指令寻址是不可能找到一字节内部的bit的,是无法指令寻址的。但是在网络中传输是按位(bit)来传输的,在网络通信中位序(bit)的概念显然还是存在的。

   TCP/IP网络通信时,位序对于上层应用都是透明的,但是数据到网卡那一层时,网卡会统一转换成小端位序,即低有效位在前的顺序发送,而接收端的网卡也会自动将接收到的位序转换成所在主机的位序(小端机的位序就是小端,大端机的位序就是大端,和字节序的大小端是一致的)。

   对于开发应用层的朋友,完全不用理会位序的概念啦,底层网卡都帮你转换好了。

### 大小端概念小端主要描述数据存储在计算机内存中的字节。对于多字节数值,例如整数 `0x12345678` 存储在个 4 字节的空间中: #### 小端模式 - **定义**: 数据的低存放在较低地址的置,高存放在较高地址的置。 - **示例**: 假设数值 `0x12345678` 被分配到起始地址为 `0x100` 的内存区域,在小端模式下的排列如下: - 地址 `0x100`: `0x78` - 地址 `0x101`: `0x56` - 地址 `0x102`: `0x34` - 地址 `0x103`: `0x12` 这种存储方式常见于 Intel x86 架构处理器[^5]。 #### 大端模式 - **定义**: 数据的高存放在较低地址的置,低存放在较高地址的置。 - **示例**: 同样假设数值 `0x12345678` 被分配到起始地址为 `0x100` 的内存区域,在大端模式下的排列如下: - 地址 `0x100`: `0x12` - 地址 `0x101`: `0x34` - 地址 `0x102`: `0x56` - 地址 `0x103`: `0x78` 这种存储方式常见于 Motorola PowerPC 或 SPARC 架构处理器[^5]。 --- ### 解决与大小端相关的问题 当程运行在不同架构的平台上时,可能会遇到因大小端差异而导致的数据不致问题。以下是几种常见的解决方案及其实现方法: #### 方法:条件编译检测平台大小端并调整域布局 可以利用预处理指令来判断当前平台是大端还是小端,并据此重新安排结构体成员的顺。例如: ```c #include <stdio.h> #include <asm/byteorder.h> struct bit_order { #if defined(__LITTLE_ENDIAN_BITFIELD) unsigned char a: 2, b: 3, c: 3; #elif defined(__BIG_ENDIAN_BITFIELD) unsigned char c: 3, b: 3, a: 2; #else #error "Please fix <asm/byteorder.h>" #endif }; int main() { unsigned char ch = 0x79; struct bit_order* ptr = (struct bit_order*)&ch; printf("bit_order->a : %u\n", ptr->a); printf("bit_order->b : %u\n", ptr->b); printf("bit_order->c : %u\n", ptr->c); return 0; } ``` 此代码片段展示了如何根据不同平台设置域字段的顺以适应各自的字节特性[^1]。 #### 方法二:使用标准化函数转换字节 在网络通信场景下,通常会涉及跨设备间传输数据的情况。为了确保接收方能够正确解析发送过来的信息包内容,往往需要统采用某种固定的字节形式——即所谓的“网络字节”,它实际上是种特定的大端表示法。可以通过调用诸如 `htonl()`(将无符号长整形从主机字节转化为网络字节)、`ntohl()` (反向操作)之类的库函数完成必要的变换过程[^3]。 --- ### 示例代码展示 下面给出段简单的 C++ 程用来演示如何判定系统的字节以及执行相应的转换动作: ```cpp #include <iostream> using namespace std; // 判断系统是否为Little Endian bool is_little_endian(){ short int number = 0x1; return *(char*)(&number) == 1; } void convert_to_network_order(uint32_t& value){ if(is_little_endian()){ uint32_t temp = ((value << 24) & 0xFF000000 ) | ((value << 8) & 0x00FF0000 ) | ((value >> 8) & 0x0000FF00 ) | ((value >> 24) & 0x000000FF ); value = temp; } } int main(){ cout<<"System Byte Order:"<<endl; if(is_little_endian())cout<<"\tLittleEndian"<<endl; else cout<<"\tBigEndian"<<endl; uint32_t num=0x12345678; cout<<hex<<"Original Number:\t"<<num<<dec<<endl; convert_to_network_order(num); cout<<hex<<"After Conversion:\t"<<num<<dec<<endl; return 0; } ``` 该例子首先定义了个辅助功能用于识别目标环境属于哪种类别的字节列;接着提供了种手动实施由本地格式转变为网络兼容版本的方法。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值