字节序
字节序,顾名思义,就是字节组织的顺序。我们可以将其根据其存储时从低位开始还是从高位开始分为两种,具体如下:
类型 | 简写 | 本质 |
---|---|---|
大端 | BE(big endian) | 将高序字节存储在起始地址 |
小端 | LE(little endian) | 将低序字节存储在起始地址 |
这就是大小端序的含义,两者除了顺序上没有其他的区别,在性能上、功能上都是一样的。
注意:
- 网络协议指定了通讯字节序为大端
- 只有在多字节数据作为整体处理时才需要考虑字节序
- 运行在同一台计算机上的进程相互通信时,一般不用考虑字节序
- 异构计算机之间通讯,需要转换自己的字节序为网络字节序
lscpu
可以用于查看当前CPU的字节序
从代码角度理解字节序
为了更好的理解,我们实现这样一个功能,定义一个int型变量,它占四个字节,再定义一个char型数组,将int型变量中的内容拷贝进char型数组中,又因为char型变量占一个字节,所以我们定义的这个char型数组中至少有4个变量.
具体代码如下:
#include <iostream>
#include <cstring>
using namespace std;
int main(){
int n=12345678;
cout << hex << n << endl;
char c[4];
memcpy(c, &n, 4);
for(auto a:c){
cout << (short)a << endl;
}
}
运行结果如下:
第一行输出即是变量n的十六位进制输出,将其拷贝进char型数组中,输出的第一个变量为4e,而4e在变量n中却是低比特位,故而在我的linux系统中使用的是小端。
两种字节序优缺点
-
小端优点:符合人的思维的字节序地址低位存储值的低位地址高位存储值的高位。从人的第一观感来说低位值小,就应该放在内存地址小的地方,也即内存地址低位;反之,高位值就应该放在内存地址大的地方,也即内存地址高位。
-
大端优点:直观的字节序地址,不要考虑对应关系只需要把内存地址从左到右按照由低到高的顺序写出,把值按照通常的高位到低位的顺序写出两者对照,一个字节一个字节的填充进去。
字节序转换函数
网络字节顺序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节顺序采用大端排序方式。
不同的CPU有不同的字节序类型 这些字节序是指整数在内存中保存的顺序 这个叫做主机序。两大CPU派系中的PowerPC系列采用大端方式存储数据,而x86系列则采用小端方式存储数据。所以在某些时刻需要对字节序进行转换。
网络序转主机序
使用的函数如下:
函数 | 含义 | 作用 |
---|---|---|
ntohs() | network to host short | 把unsigned short类型从网络序转换到主机序 |
ntohl() | network to host long | 把unsigned long类型从网络序转换到主机序 |
具体相关代码如下:
#include <iostream>
#include <cstring>
#include <arpa/inet.h>
using namespace std;
int main(){
int n = 12345678;
cout << hex << n << endl;
char c[4];
int m = htonl(n);
memcpy(c, &m, 4);
for(auto a:c){
cout << (short)a << " ";
}
cout << endl;
}
运行结果如下:
显然原变量的高位存储在了高位上,将我们的小端序转为了大端序。
主机序转网络序
函数 | 含义 | 作用 |
---|---|---|
htons() | host to network short | 把unsigned short类型从主机序转换到网络序 |
htonl() | host to network long | 把unsigned long类型从主机序转换到网络序 |
我们以上文的代码为基础,将大端转为小端,具体代码实现如下:
#include <iostream>
#include <cstring>
#include <arpa/inet.h>
using namespace std;
int main(){
int n = 12345678;
cout << hex << n << endl;
char c[4];
int m = htonl(n);
memcpy(c, &m, 4);
for(auto a:c){
cout << (short)a << " ";
}
cout << endl;
int b = ntohl(m);
cout << b << endl;
}
运行结果如下:
显然我们此时又将其转化为小端序。