字节序

对于字符串来说,是没有字节序的差别的,就像我们写字,内存就像是纸,字符串就从左向右依次写:

内存地址:00000000 00000001 00000002 00000003 …

内存数据: ‘A’ ‘B’ ‘C’ ‘D’

而任何cpu读取的时候,也都是从左向右依次读取。

对于多字节数据(比如short、int、long…),不同字节序是有差别的。

所有x86架构cpu(包括x64)都是用的小端字节序,网络字节序是大端序:

int a = 0x01020304;

内存地址:00000000 00000001 00000002 00000003 …

大端序a : 0x01 0x02 0x03 0x04 即cpu读出的数据从高向低位写入变量

小端序a : 0x04 0x03 0x02 0x01 即cpu读出的数据从低向高位写入变量

如果我们写的程序不进行字节序转换会怎么样呢:

int a = 0x01020304;

在我们x86架构机器的内存里,它是这样写的0x04030201(注意,这是它在内存里的真实写法,当我们的程序以int型读取的时候才会转化成0x01020304),此时进行网络发送,send程序会以字节的方式(可以把它想象成字符串),一字节一字节的发送,到了网络上,它的顺序仍然是0x04030201(此时它的顺序已经错了)。当数据到达对端机器的时候,对端机器也是一字节一字节的收入内存,它的顺序仍然是0x04030201。如果对端仍是x86架构,那么数据读出来的时候它又被转化成了0x01020304,这看起来像是对的。但是如果对端是大端序的架构,那么它的int型数据就变成了0x04030201。

字节序转换:

linux里提供了现成的函数:htonl, ntohl … 这是一系列函数,却只提供了2字节和4字节的转换。

判断字节序:

1
2
3
4
5
6
7
8
9
int is_big_endian(void) {
int test = 0x12345678;
char *p = (char *)&p;
if(*p = 0x12)
return 1;
else
return 0;
}

函数虽然简陋,但是已经够用了。

此外

http://c.biancheng.net/cpp/html/3047.html

注意:为 sockaddr_in 成员赋值时需要显式地将主机字节序转换为网络字节序,而通过 write()/send() 发送数据时TCP协议会自动转换为网络字节序,不需要再调用相应的函数。

坚持原创技术分享,您的支持将鼓励我继续创作!