这是我的博客真正内容的第一篇,就从最近工作上遇到的一个问题开始吧——大小端字节序
首先我先从简单的概念开始介绍大小端字节序吧:
概念:
字节序是指多字节数据在计算机内存中存储或者网络传输时各字节序的存储顺序(我从网上找到的,个人认为这句表达的已经很明确了)
下面是常见的字节序:
1、Little endian(小端字节序LE):就是低位放在低地址,高位放在高地址;
2、Big endian(大端字节序BE):就是低位放在高地址,高位放在低地址;
eg:将0x12345678写到以0x0000开始的内存中,有以下结论:
地址 LE BE
0x0000 0x78 0x12
0x0001 0x56 0x34
0x0002 0x34 0x56
0x0003 0x12 0x78
以上就是最基本的知识点了,下面介绍做项目需要的一些基础知识吧:
网络字节序:
网络字节序是TCP/IP中规定的一种数据表示格式,这与操作系统、CPU等无关,这里我们应该察觉到,既然与操作系统以及硬件无关的话,说明在TCP/IP的协议之下,信息的传输是不需要做大写端字节序的转换的,我想这也是TCP/IP协议的一个强大之处,还有一点就是网络字节顺序都是采用BE,也就是上面我们所介绍的大端字节序
既然有了这几种字节序,那么我们可以想象,当两台不同字节序的主机之间进行通信的话,如果我们不采取一定的措施,比如说上面的例子中,就会被解释为不同的数据,这就会造成数据的错乱,这样的话,你要做的项目自然会是以失败告终,那么如何处理类似这种事件呢?下面我来介绍一下大小端字节序、以及大小端字节序与网络字节序是如何进行转换的:
其实很简单比如说在一个系统中一个数被理解为A-B-C-D(A/B/C/D各占8位),我们只要把它变为D-C-B-A即可。下面是一个宏块的操作:
#define ChangeEndian(in) ( ( (in >> 24) & 0xff) | ( (in >> 8) & 0xff00) | ( (in << 8) & 0xff0000) | (in << 24))/*4字节*/
#define ChangeEndian(in) ( ( (in >> 8) & 0xff) | (in << 8))/*2字节*/
上面两个语句,就是实现大小端字节序的转换,具体的理解,大家可以按照实现的方法来一遍,其实也挺简单的;好了下面我将介绍几个函数(bsd socket提供的转换函数),这几个函数在网络通信时有存在的必要
1、htons()把unsigned short类型从主机序转换到网络序
2、htonl()把unsigned long类型从主机序转换到网络序
3、ntohs()把unsigned short类型从网络序转换到主机序
4、ntohl()把unsigned long类型从网络序转换到主机序
由于网络字节序都是BE,所以在BE类型的系统中,这些函数定义成空宏。
在做到网络开发或者是跨平台项目时,需要注意字节序的问题。
下面是我自己写的一个简单的测试系统的字节序的程序
#include <stdio.h>
#define ChangeEndian(in) ( ( (in >> 24) & 0xff) | ( (in >> 8) & 0xff00) | ( (in << 8) & 0xff0000) | (in << 24))/*4字节*/
int main(int argc, char** argv)
{
int i_num = 0x12345678;
int j_num = 0x12;
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) );
if(j_num == *((char*)&i_num + 3))
{
printf("The endian of this System is LE\n");
}
else
{
printf("The endian of this System is BE\n");
}
return 1;
}
对于枚举类型的数据进行转换时需要强制转换一下,再赋值给原变量