C语言大小端字节序存储模式深入解读
介绍
在计算机存储体系中,一个数据在内存中是以若干字节为单位连续存储的。对于多字节数据的存储顺序,有两种规定:大端序和小端序,又分别称为网络字节序和主机字节序。C语言内存系统的存储方式是与它所运行的机器硬件有关的。在探讨之前,首先对大小端进行简单的介绍。
机器内存中的数据,大端和小端这两种存储方式主要考虑的是字节序。在计算机中,一个整型数字在内存中所占的大小是4个字节,这个4字节中并不是按照这个数据的本意进行存储的,而是分成了4个字节连续存储到内存中。
- 大端序:将高位字节存放在内存的低地址端,低位字节存放在内存的高地址端。例如数字 0x12345678 在内存中的表示形式是
12 34 56 78
。 - 小端序:将低位字节存放在内存的低地址端,高位字节存放在内存的高地址端。例如数字 0x12345678 在内存中的表示形式是
78 56 34 12
。
C语言中的字节序函数
C语言中提供了函数 htonl()
和 ntohl()
来实现大端字节序与小端字节序转化。字母 h
表示主机(Host
),n
表示网络(Network
),l
表示 32 位字长(long
)。这两个函数主要用于将本地字节序转化成网络字节序:
uint32_t htonl(uint32_t hostlong);
uint32_t ntohl(uint32_t netlong);
htonl()
函数将 4 字节(32 位)的本机无符号整数转换为网络字节序无符号整数;ntohl()
函数将 4 字节的网络字节序无符号整数转换为本机字节序的无符号整数。
因此,我们在网络通信中经常会用到这两个函数。
示例1
以十进制整数 16909060 (二进制表示为 00000001 00000010 00000011 00000100
) 为例,分别以大小端字节序存储。
当以大端模式存储时,每一位的存储是这样的:
低地址 | 0x04 | 0x03 | 0x02 | 0x01 | 高地址 |
---|---|---|---|---|---|
00000001 | 00000010 | 00000011 | 00000100 |
当以小端模式存储时,每位的存储是这样的:
低地址 | 0x01 | 0x02 | 0x03 | 0x04 | 高地址 |
---|---|---|---|---|---|
00000001 | 00000010 | 00000011 | 00000100 |
示例2
在网络通信中,大端序是常用的网络字节序。下面介绍一个常见的网络通信的示例,计算机通过 socket 发送一个二进制数据包。下面分别以大端序和小端序来表示这个二进制数据包的字节序。
大端序
以一个 4 字节的数据 0x12345678 为例,其大端序的存储方式为 12 34 56 78
,因此在向网络传输时,需要先将主机字节序转化为大端字节序,再进行网络通信。
#include <stdio.h>
#include <netinet/in.h>
int main() {
uint32_t num = 0x12345678;
uint32_t net = htonl(num); // 转换成大端序
// 发送数据,注意这里使用的是大端序
send(sock, &net, sizeof(net), 0);
return 0;
}
小端序
如果采用小端序来实现网络通信的话,需要将主机字节序转化为小端字节序,并发送小端序的数据。
#include <stdio.h>
#include <netinet/in.h>
int main() {
uint32_t num = 0x12345678;
// 使用小端序
uint32_t net = (num >> 24) | ((num << 8) & 0x00FF0000) | ((num >> 8) & 0x0000FF00) | (num << 24);
// 发送数据,这里使用的是小端序
send(sock, &net, sizeof(net), 0);
return 0;
}
需要注意的是,在网络通信中,服务器和客户端要保证使用同一种字节序。如果一个是大端字节序,一个是小端字节序,就会发生数据解析错误。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C语言大小端字节序存储模式深入解读 - Python技术站