大端法、小端法、网络字节序

本文详细介绍了字节序的概念,包括大端法与小端法的区别,并通过实例展示了80X86平台上的字节序特点及如何使用 htonl 函数进行字节序转换。

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

关于字节序(大端法、小端法)的定义
《UNXI网络编程》定义:术语“小端”和“大端”表示多字节值的哪一端(小端或大端)存储在该值的起始地址。小端存在起始地址,即是小端字节序;大端存在起始地址,即是大端字节序。

 

也可以说: 
1.小端法(Little-Endian)就是低位字节排放在内存的低地址端即该值的起始地址,高位字节排放在内存的高地址端。 
2.大端法(Big-Endian)就是高位字节排放在内存的低地址端即该值的起始地址,低位字节排放在内存的高地址端。

举个简单的例子,对于整形0x12345678。它在大端法和小端法的系统内中,分别如图1所示的方式存放。

zijiexu_pic_1 

 

网络字节序

我们知道网络上的数据流是字节流,对于一个多字节数值,在进行网络传输的时候,先传递哪个字节?也就是说,当接收端收到第一个字节的时候,它是将这个字节作为高位还是低位来处理呢? 
网络字节序定义:收到的第一个字节被当作高位看待,这就要求发送端发送的第一个字节应当是高位。而在发送端发送数据时,发送的第一个字节是该数字在内存中起始地址对应的字节。可见多字节数值在发送前,在内存中数值应该以大端法存放。 
网络字节序说是大端字节序。 
比如我们经过网络发送0x12345678这个整形,在80X86平台中,它是以小端法存放的,在发送前需要使用系统提供的htonl将其转换成大端法存放,如图2所示。

zijiexu_pic_2

 

字节序测试程序 
不同cpu平台上字节序通常也不一样,下面写个简单的C程序,它可以测试不同平台上的字节序。
#include <stdio.h>
#include <netinet/in.h>
int main()
{
    int i_num = 0x12345678;
    printf("[0]:0x%x\n", *((char *)&i_num + 0));
    printf("[1]:0x%x\n", *((char *)&i_num + 1));
    printf("[2]:0x%x\n", *((char *)&i_num + 2));
    printf("[3]:0x%x\n", *((char *)&i_num + 3));
10   
11      i_num = htonl(i_num);
12      printf("[0]:0x%x\n", *((char *)&i_num + 0));
13      printf("[1]:0x%x\n", *((char *)&i_num + 1));
14      printf("[2]:0x%x\n", *((char *)&i_num + 2));
15      printf("[3]:0x%x\n", *((char *)&i_num + 3));
16   
17      return 0;
18  } 


在80X86CPU平台上,执行该程序得到如下结果: 
[0]:0x78 
[1]:0x56 
[2]:0x34 
[3]:0x12

[0]:0x12 
[1]:0x34 
[2]:0x56 
[3]:0x78

分析结果,在80X86平台上,系统将多字节中的低位存储在变量起始地址,使用小端法。htonl将i_num转换成网络字节序,可见网络字节序是大端法。

总结点:80X86使用小端法,网络字节序使用大端法。


今天在网上看到一篇关于htonl()函数的解释,感觉有道理,贴过来大家一起学习!微笑

htonl就是把本机字节顺序转化为网络字节顺序

h---host 本地主机
to  就是to 了
n  ---net 网络的意思
l 是 unsigned long

与此类似的是htons()

s是unsigned short

所谓网络字节顺序(大尾顺序)就是指一个数在内存中存储的时候“高对低,低对高”(即一个数的高位字节存放于低地址单元,低位字节存放在高地址单元中)。但是计算机的内存存储数据时有可能是大尾顺序或者小尾顺序。

先举个例子:
int a = 0x403214;
int b = htonl(a);
我在VC++6.0调试这段代码,发现
&a的值为:0x0012ff44
其中0x0012ff44、0x0012ff45、0x0012ff46、0x0012ff47这四个单元的值依次为:14、32、40、00,即0x403214这个数的高位部分存放在高位地址中,低位部分存放在低位地址中,即小尾顺序。
&b的值为:0x0012ff40
其中0x0012ff40、0x0012ff41、0x0012ff42、0x0012ff43这四个单元的值依次为:00、40、32、14,即把原数0x403214的高位部分存放在低位地址中,低位部分存放在高位地址中。
由此可见,如果一个数以小尾顺序存储,经htonl函数调用后这个数的高地位字节会完全颠倒过来成为一个新的数。这个新的数在机器内部其实还是以小尾顺序存储的,但是相对于原来的数而言相当于是变成大尾顺序的了。
long型的0x40写完整为:0x 00 00 00 40,共四个字节,调用htonl后四个字节颠倒顺序,为0x 40 00 00 00。
同样,0x40 00 00 00调用htonl后变为0x 00 00 00 40,即0x40 

<think>好的,我现在需要帮助用户了解C++中整型数据的大端小端存储方式。首先,我需要回顾用户提供的引用内容,看看哪些信息可以直接使用。引用1、3、4、5都提到了大小端的检测方,特别是通过将整数1的字节表示来判断。用户之前的问题也涉及整型的存储,所以需要结合这些内容。首先,我应该解释什么是大端小端存储。根据引用5,小端是高位存在高位内存,而大端是高位存在低位内存,符合人类习惯。需要用例子说明,比如整数0x12345678的存储方式。接下来,用户可能想知道如何在C++中检测大小端。引用1、3、4中的代码示例展示了如何通过将int转换为char指针来检查第一个字节是否为1。我需要将这些方整合成一个清晰的步骤,并给出代码示例。另外,用户提到引用2中的转换函数,可能还想知道如何转换字节顺序。这部分需要解释转换的原理,比如使用位移和掩码操作,或者使用库函数如htonl和ntohl。还需要注意数据对齐的问题,引用5提到数据对齐的原因,但用户的问题主要集中在大小端,所以可能不需要深入讨论对齐,但可以简要提及。用户可能的应用场景包括网络编程和跨平台数据传输,这时候处理字节序很重要。需要举例说明这些场景下的最佳实践,比如使用网络字节序大端)和转换函数。最后,生成相关的问题,比如检测方、转换方网络编程中的应用,以及不同架构的影响。确保问题覆盖用户可能进一步探索的方向。在写作时,要确保结构清晰,分点解释,代码示例正确,并且引用标记正确。同时,要使用中文,避免使用Markdown格式,但按照用户的要求,最终回答需要使用特定的格式,包括引用标识和代码块。需要检查是否有遗漏的引用,并正确标注。 可能还需要指出,C++标准本身没有规定字节序,所以程序不应该依赖特定字节序,除非处理外部数据。这时,转换函数如引用2中的模板函数就派上用场了。需要解释这个模板函数的工作原理,如何将任意整型转换为小端存储。总结,回答的结构应该是:定义大小端、检测方、转换方、应用场景和注意事项,最后相关问题。确保每个部分都有引用支持,并自然添加引用标记。</think>### C++整型数据的大端/小端存储方式详解 --- #### 一、基本概念 1. **大端序(Big-Endian)** - **高位字节存储在低地址**,符合人类阅读习惯 - 示例:数值 `0x12345678` 存储为 `12 34 56 78`(从左到右地址递增)[^5] 2. **小端序(Little-Endian)** - **低位字节存储在低地址**,Intel架构常用 - 示例:数值 `0x12345678` 存储为 `78 56 34 12`[^5] --- #### 二、检测方 1. **指针检测** ```cpp bool is_little_endian() { int num = 1; return *(reinterpret_cast<char*>(&num)) == 1; // 取第一个字节判断 } ``` - 原理:小端序中最低有效字节存储在最低地址[^1][^3] 2. **联合体检测** ```cpp union EndianChecker { int value; char bytes[4]; }; bool check_endian() { EndianChecker ec{1}; return ec.bytes[0] == 1; // 小端返回true } ``` - 利用联合体共享内存空间的特性[^4] --- #### 三、字节序转换 1. **手动转换模板** ```cpp template <typename T> T to_big_endian(T value) { size_t size = sizeof(T); T result = 0; for (size_t i = 0; i < size; ++i) { result |= ((value >> (8 * i)) & 0xFF) << (8 * (size - 1 - i)); } return result; } ``` - 将任意整型转换为大端序[^2] 2. **系统函数** - 使用 `htonl()`(32位)、`htons()`(16位)等网络字节序函数 ```cpp uint32_t network_order = htonl(host_order); // 主机序→网络序(大端) ``` --- #### 四、应用场景 1. **网络通信** - 网络协议默认使用大端序,需转换本地数据[^2] 2. **文件格式解析** - 如JPEG文件头使用大端序存储元数据 3. **跨平台开发** - 不同架构设备(ARM/Intel)间数据交换时需统一字节序 --- #### 五、注意事项 1. **不可移植性** ```cpp // 错误示例:直接读取二进制内存 int read_value = *reinterpret_cast<int*>(network_buffer); // 可能因字节序错误 ``` 2. **数据对齐问题** - 跨平台传输时需考虑结构体填充(使用 `#pragma pack` 控制对齐)[^5] --- #### 示例代码 ```cpp #include <iostream> #include <arpa/inet.h> // 包含htonl等函数 int main() { uint32_t host_value = 0x12345678; uint32_t network_value = htonl(host_value); std::cout << "主机序: 0x" << std::hex << host_value << "\n" << "网络序: 0x" << network_value << std::endl; return 0; } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值