大端存储
现有4字节存储的整数 0x0A0B0C0D,内存中存放方式如下:
最高位字节是0x0A存储在最低的内存地址处。下一个字节0x0B存储于随后的地址。类似于十六进制字节从左到右的阅读顺序。
小端存储
与大端存储正好相反。最高字节存储在高的内存地址处。
同样的现有4字节存储的整数 0x0A0B0C0D,内存中存放方式如下:
大小端的判断方式
例一:
#include <stdio.h>
#include <stdint.h>
int main()
{
uint16_t a = 0x1122;
if (*(uint8_t*)&a == 0x22) {
printf("little endian.\n");
} else {
printf("big endian.\n");
}
}
例二:
int main()
{
union u_a {
short int a;
char b;
} u_a_u;
u_a_u.a = 0x1122;
if (u_a_u.b == 0x22) {
printf("little endian.\n");
} else {
printf("big endian.\n");
}
}
例三
uint32_t little_endian_system_check()
{
const int16_t n = 1;
if (*(char *)&n) {
printf("little endian.\n");
}
printf("big endian.\n");
}
字节序
又称端序或尾序(英语:Endianness),在计算机科学领域,指存储器中或在数字通信链路中,组成多字节的字的字节的排列顺序。
网络字节序
TCP/IP协议隆重出场,RFC1700规定使用**“大端”字节序为网络字节序**,其他不使用大端的计算机要注意了,发送数据的时候必须要将自己的主机字节序转换为网络字节序(即“大端”字节序),接收到的数据再转换为自己的主机字节序。这样就与CPU、操作系统无关了,实现了网络通信的标准化。
字节序转换函数
Berkeley套接字定义了一组转换函数,用于16和32bit整数在网络序和主机字节序之间的转换。
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong); //把uint32_t类型从主机序转换到网络序
uint16_t htons(uint16_t hostshort); //把uint16_t类型从主机序转换到网络序
uint32_t ntohl(uint32_t netlong); //把uint32_t类型从网络序转换到主机序
uint16_t ntohs(uint16_t netshort); //把uint16_t类型从网络序转换到主机序
以下是自己实现的一个64位数值的字节序转换的函数:
#define swap_64(ll_data)\
((((ll_data) & 0xff00000000000000ull) >> 56) \
| (((ll_data) & 0x00ff000000000000ull) >> 40) \
| (((ll_data) & 0x0000ff0000000000ull) >> 24) \
| (((ll_data) & 0x000000ff00000000ull) >> 8) \
| (((ll_data) & 0x00000000ff000000ull) << 8) \
| (((ll_data) & 0x0000000000ff0000ull) << 24) \
| (((ll_data) & 0x000000000000ff00ull) << 40) \
| (((ll_data) & 0x00000000000000ffull) << 56))
uint64_t htonll(uint64_t ll_data)
{
return little_endian_system_check() ? swap_64(ll_data) : ll_data;
}
uint64_t ntohll(uint64_t ll_data)
{
return little_endian_system_check() ? swap_64(ll_data) : ll_data;
}
套接字地址结构
IPv4地址和TCP或UDP端口号在套接字地址结构中总是以网络字节序来存储。
比特序
比特序就是一个字节中的8个比特位(bit)之间的顺序问题。一般情况下系统的比特序和字节序是保持一致的。