操作系统中的大头小头字节序

博客介绍了网络字节序与主机字节序,常见的主机序有Little endian和Big endian两种,并举例说明了它们在内存中的存储方式。还通过实验展示了汉字“严”在GB2312、Unicode、Unicode big endian、UTF - 8编码下的机器码及存储方式。

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

网络字节序与主机字节序

 

不同的CPU有不同的字节序类型 这些字节序是指整数在内存中保存的顺序 这个叫做主机序

最常见的有两种

1. Little endian(小头):将序字节存储在起始地址

2. Big endian(大头):将序字节存储在起始地址

 

内存地址: (起始地址)低位 ------> 高位

二进制编码: 0x高位|低位  

FE FF : 大头,最直观

FF FE:小头,需要颠倒              

 

LE little-endian

最符合人的思维的字节序

地址低位存储值的低位

地址高位存储值的高位

怎么讲是最符合人的思维的字节序,是因为从人的第一观感来说

低位值小,就应该放在内存地址小的地方,也即内存地址低位

反之,高位值就应该放在内存地址大的地方,也即内存地址高位

 

BE big-endian

最直观的字节序

地址低位存储值的高位

地址高位存储值的低位

为什么说直观,不要考虑对应关系

只需要把内存地址从左到右按照由低到高的顺序写出

把值按照通常的高位到低位的顺序写出

两者对照,一个字节一个字节的填充进去

 

例子:在内存中双字0x01020304(DWORD)的存储方式

 

内存地址

4000 4001 4002 4003

LE 04 03 02 01

BE 01 02 03 04

 

例子:如果我们将0x1234abcd写入到以0x0000开始的内存中,则结果为

      big-endian   little-endian

0x0000   0x12       0xcd

0x0001   0x23       0xab

0x0002   0xab       0x34

0x0003   0xcd       0x12

 

 

实验:

用sublime显示汉字 “严”在ANSIUnicodeUnicode big endianUTF-8编码方式下对应的机器码。

ANSI:    文件的编码显示 D1 CF, 这正是“严”的 GB2312 编码,这也暗示 GB2312 是采用大头方式存储的

Unicode:  编码是四个字节 FF FE 25 4E,其中FF FE表明是小头方式存储,真正的编码是4E25

Unicode big endian: 编码是四个字节 FEFF 4E 25, 其中FEFF表示大头方式存储,因此与直观感受一样(即:编码顺序和存储顺序相同),真正的编码即为4E25

 

UTF-8: 编码是六个字节EF BB BF E4 B8 A5,前三个字节EF BB BF表示这是UTF-8编码,后三个E4B8A5就是的具体编码,它的存储顺序与编码顺序是一致的。

例如:chen25陈 的UTF-8编码为

同样以EF BB BF开头

 


资料:

https://blog.youkuaiyun.com/sunstars2009918/article/details/7274519 

http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html

 

<think>我们正在讨论的是在定义变量时涉及的“大头封”和“小头封”概念。实际上,这里指的是计算机体系结构中的字节序(Endianness)问题,即数据在内存中存储的字节顺序。通常分为大端序(Big-Endian)和小端序(Little-Endian)。 ### 字节序的概念 - **大端序(Big-Endian)**:数据的高位字节存储在低地址,低位字节存储在高地址。例如,十六进制数`0x12345678`在内存中的存储(从低地址到高地址)为:`12 34 56 78`。 - **小端序(Little-Endian)**:数据的低位字节存储在低地址,高位字节存储在高地址。同样,`0x12345678`的存储顺序为:`78 56 34 12`。 ### 定义变量时的处理 在定义变量时,我们通常不需要显式处理字节序,因为编译器会根据目标平台的字节序自动处理。但是,在以下情况下需要特别注意: 1. **跨平台数据传输**:当数据在不同字节序的平台之间传输时(如通过网络发送),需要统一字节序(通常使用网络字节序,即大端序)。 2. **处理二进制数据**:当读取或写入二进制文件、网络数据包或硬件寄存器时,需要明确数据的字节序。 ### 处理方法 1. **检测系统字节序**:可以使用代码来检测当前系统的字节序。例如,通过一个整数(如`0x01020304`)的字节表示来判断: ```c #include <stdio.h> int main() { unsigned int num = 0x01020304; unsigned char *p = (unsigned char *)&num; if (*p == 0x04) { printf("Little-Endian\n"); } else if (*p == 0x01) { printf("Big-Endian\n"); } return 0; } ``` 2. **转换字节序**:如果需要在不同字节序的系统间交换数据,可以使用以下函数进行转换: - **主机字节序转网络字节序**(大端序): ```c uint32_t htonl(uint32_t hostlong); // 32位整数 uint16_t htons(uint16_t hostshort); // 16位整数 ``` - **网络字节序转主机字节序**: ```c uint32_t ntohl(uint32_t netlong); uint16_t ntohs(uint16_t netshort); ``` 3. **手动转换**:如果没有现成的函数,可以手动进行字节交换。例如,将一个32位整数从主机序转换到大端序(如果主机是小端序): ```c uint32_t to_big_endian(uint32_t value) { return ((value >> 24) & 0xff) | // 移动最高8位到最低8位 ((value >> 8) & 0xff00) | // 移动次高8位到次低8位 ((value << 8) & 0xff0000) | // 移动次低8位到次高8位 ((value << 24) & 0xff000000); // 移动最低8位到最高8位 } ``` ### 示例 假设我们在小端序系统上有一个32位整数`0x12345678`,需要将其转换为大端序字节流: - 小端序内存布局:`78 56 34 12`(低地址到高地址) - 转换为大端序后:`12 34 56 78`(低地址到高地址) ### 总结 在定义变量时,通常不需要考虑字节序,因为编译器会处理。但在跨平台数据交换时,必须确保使用一致的字节序(通常使用网络字节序)。处理字节序的方法包括使用系统提供的转换函数或手动进行字节交换[^3][^4]。 §§相关问题§§ 1. 如何判断当前系统是大端序还是小端序? 2. 在网络编程中如何处理字节序问题? 3. 字节序对文件读写有什么影响? 4. 除了大端序和小端序,还有其他字节序吗?</think>### 大头序与小头序(字节序)详解 在计算机系统中定义变量时,"大头封"和"小头封"指的是**字节存储顺序**(Endianness),即多字节数据在内存中的存储方式。这是系统架构层面的重要概念,直接影响数据的解析方式。 #### 1. 核心概念 - **大头序(Big-Endian)**: - 高字节存储在低地址(类似人类阅读顺序) - 示例:`0x12345678` 存储为 `12 34 56 78`(地址递增) - 常见于:网络传输(TCP/IP)、Java虚拟机、IBM PowerPC - **小头序(Little-Endian)**: - 低字节存储在低地址(反向存储) - 示例:`0x12345678` 存储为 `78 56 34 12`(地址递增) - 常见于:x86/x64架构、ARM处理器(默认) #### 2. 定义变量时的处理方法 当定义多字节变量(如int, float)时: ```c uint32_t num = 0x12345678; // 定义4字节变量 ``` 内存存储差异: | 内存地址 | 大头序 | 小头序 | |----------|--------|--------| | 0x0000 | 0x12 | 0x78 | | 0x0001 | 0x34 | 0x56 | | 0x0002 | 0x56 | 0x34 | | 0x0003 | 0x78 | 0x12 | [^3] #### 3. 关键处理技术 **(1) 检测系统字节序** ```c #include <stdint.h> int is_little_endian() { uint32_t num = 0x1; uint8_t *p = (uint8_t*)# return (*p == 0x1); // 首字节为1则是小头序 } ``` [^3] **(2) 字节序转换函数** ```c // 32位转换(主机序 ↔ 网络序) uint32_t htonl(uint32_t hostlong); // 主机→网络(大头) uint32_t ntohl(uint32_t netlong); // 网络→主机 ``` **(3) 手动转换** ```c uint32_t swap_endian(uint32_t val) { return ((val >> 24) & 0xFF) | ((val >> 8) & 0xFF00) | ((val << 8) & 0xFF0000) | ((val << 24) & 0xFF000000); } ``` #### 4. 应用场景处理 - **网络编程**:必须使用大头序(网络字节序) ```c uint32_t data = 0x12345678; uint32_t net_data = htonl(data); // 发送前转换 ``` - **文件读写**:跨平台文件需统一字节序 - **硬件交互**:外设寄存器可能使用特定字节序 #### 5. 重要注意事项 1. 单字节变量(如`char`)不受影响 2. 结构体成员顺序影响内存布局: ```c struct { // 小头序内存布局: uint16_t a; // 低地址 → a低字节 uint32_t b; // a高字节 → b低字节 }; // b后续字节... ``` 3. 联合体(union)可用于直接访问字节: ```c union { uint32_t num; uint8_t bytes[4]; } endian_test; ``` > 理解字节序对处理网络协议、二进制文件、加密算法和跨平台开发至关重要。在定义变量时,应始终考虑数据的使用场景和运行环境[^3][^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值