您的位置:首页 > 其它

字节存储排序:大端和小端的判别及转换

2012-09-16 14:07 155 查看
转自:http://www.cosdiv.com/page/M0/S670/670783.html

当前的存储器,多以byte为接见的最小单位,当一个逻辑上的地址必须分别为物理上的若干单位时就存在了先放谁后放谁的题目,于是端(endian)的题目应运而生了,对于不合的存储办法,就有大端(big-endian)和小端(little- endian)两个描述。

字节排序按分为大端和小端,概念如下

大端(big endian):低地址存放高有效字节

小端(little endian):低字节存放地有效字节

现在主流的CPU,intel系列的是采用的little endian的格式存放数据,而motorola系列的CPU采用的是big endian,ARM则同时支持 big和little,网络编程中,TCP/IP统一采用大端方式传送数据,所以有时我们也会把大端方式称之为网络字节序。

特别需要注意的是,C/C++语言编写的程序里数据存储顺序是跟编译平台所在的CPU相关的,而 JAVA编写的程序则唯一采用big endian方式来存储数据。这里我就只讨论C/C++语言的情况。

1.大端和小端的别式格式及断定

举个例子申明,我的机子是32位windows的体系,处理惩罚器是AMD的。对于一个int型数0 x12345678,为便利申明,这里采取16进制默示。这个数在不合字节次序存储的CPU中储存次序如下:

0 x12345678 16进制,两个数就是一字节

高有效字节——>低有效字节: 12 34 56 78

低地址位 凹凸址位

大端: 12 34 56 78

小端: 78 56 34 12

下面验证下本机CPU属于哪种字节存储次序。代码如下:

#include <iostream>

using namespace std;

typedef unsigned int UINT;

typedef unsigned char UCHAR;

int main()

{

UINT i=0 x12345678;

cout<<hex<<i<<endl;

UCHAR *p = (UCHAR*)&i;        //将i的地址传给数组指针p,实际上p指向的地址是i在内存中存储的第一个字节,大端就是0 x12,小端就是0 x78

if((*p==0 x78)&(*(p+1)==0 x56))

cout<<"小端"<<endl;

else if((*p==0 x12)&(*(p+1)==0 x34))
cout<<"大端"<<endl;
else
cout<<"这是神马字节次序呢?";

return 0;

}

调试显示时小端,我用的机子字节存储为小端体式格式。

2.大端和小端的字节转换

当两台采取不合字节序的主机通信时,在发送数据之前都必须经过字节序的转换成为收集字节序(即大端体式格式)后再进行传输。此外用C/C++在小端体式格式的机械上编写的法度与java法度互通时也要进行大端和小端的转换。

这里所谓转换就是改变字节的排序,使交互时数据对峙一致。举一个例子,还是16进制默示的数0 x12345678,在小端机械上排序为0 x78563412,当内存中如许的数传输时,在大端体式格式下就是0 x78563412这个值,与原值不合,要想与原值雷同,在传输前,在大端体式格式下就该是0 x12345678,这时原数在内存中为0 x12345678,即将原数据0 x12345678在内存存储序列为0 x12345678,也就是要转换成大端体式格式。

要传输值:12 34 56 78

不转换时,小端:78 56 34 12

转换为大端:12 34 56 78

按照上方的大端和小端字节排序,可以便利的用移位运算完成转换功能。从小端转到大端代码如下:

#include <iostream>

using namespace std;

typedef unsigned int UINT;
typedef unsigned char UCHAR;

int main()

{

UINT i=0 x12345678;

cout<<hex<<i<<endl;

UCHAR *p = (UCHAR*)&i;

UINT num,num1,num2,num3,num4;

num1=(UINT)(*p)<<24;

num2=((UINT)*(p+1))<<16;

num3=((UINT)*(p+2))<<8;

num4=((UINT)*(p+3));

num=num1+num2+num3+num4;

cout<<"num1:"<<hex<<num1<<endl;     //看num1的16进制默示,下同

cout<<"num2:"<<hex<<num2<<endl;

cout<<"num3:"<<hex<<num3<<endl;

cout<<"num4:"<<hex<<num4<<endl;

cout<<"num:"<<hex<<num<<endl;

unsigned char *q = (unsigned char*)#

if((*q==0 x78)&(*(q+1)==0 x56))

cout<<"小端"<<endl;

else if((*q==0 x12)&(*(q+1)==0 x34))

cout<<"大端"<<endl;

else

cout<<"这是神马字节次序呢?";

return 0;

}

至于说(UINT)(*p)为什么要移24位,其实是很好懂得的,将0 x00000012变成0 x12000000,不就是向左移24位吗。

当然,向上方如许写时为了便利懂得,可以更简单的写一个函数用于完成上方的转换功能,函数如下:

UINT EndianConvertLToB(UINT InputNum) {

UCHAR *p = (UCHAR*)&InputNum;

return(((UINT)*p<<24)+((UINT)*(p+1)<<16)+

((UINT)*(p+2)<<8)+(UINT)*(p+3));

}

同样的道理实用于大端转小端,然则大端转小端时移位有差别,函数如下:

UINT EndianConvertBToL(UINT InputNum) {

UCHAR *p = (UCHAR*)&InputNum;

return(((UINT)*p)+((UINT)*(p+1)<<8)+

((UINT)*(p+2)<<16)+(UINT)*(p+3)<<24);

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: