little endian和big endian是表示计算机字节顺序的两种格式,所谓的字节顺序指的是长度跨越多个字节的数据的存放形式.
假设从地址0x00000000开始的一个字中保存有数据0x1234abcd,那么在两种不同的内存顺序的机器上从字节的角度去看的话分别表示为:
1)little endian:在内存中的顺序是0x00000000-0xcd,0x00000001-0xab,0x00000002-0x34,0x00000003-0x12
2)big endian:在内存中的顺序是0x00000000-0x12,0x00000001-0x34,0x00000002-0xab,0x00000003-0xcd
需要特别说明的是,以上假设机器是每个内存单元以8位即一个字节为单位的.
简单的说,little endian把低位存放到高位,而big endian把低位存放到低位.
现在主流的CPU,intel系列的是采用的little endian的格式存放数据,而motorola系列的CPU采用的是big endian.
以下是判断字节存储顺序的可移植的C语言代码:
/**/
/*
*******************************************************************
created: 2006-9-5
filename: test.cpp
author: 李创
purpose: 可移植的用于判断存储格式是
little endian还是big ednian的C代码
取自<<C: A Reference Manual>>
********************************************************************
*/
#include
<
stdio.h
>
union
{
long
Long;
char
Char[
sizeof
(
long
)];
}
u;
int
main()
{
u.Long
=
1
;
if
(u.Char[
0
]
==
1
)
{
printf(
"
Little Endian!\n
"
);
}
else
if
(u.Char[
sizeof
(
long
)
-
1
]
==
1
)
{
printf(
"
Big Endian!\n
"
);
}
else
{
printf(
"
Unknown Addressing!\n
"
);
}
printf(
"
Now, Let's look at every byte in the memory!\n
"
);
for
(
int
i
=
0
; i
<
sizeof
(
long
);
++
i)
{
printf(
"
[%x] = %x\n
"
,
&
u.Char[i], u.Char[i]);
}
return
0
;
}
很多人认为掌握这个知识是不必要,其实不然.在网络编程中,TCP/IP统一采用big endian方式传送数据,也就是说,假设现在是在一个字节顺序是little endian的机器上传送数据,要求传送的数据是0XCEFABOBO,那么你就要以0XBOBOFACE的顺序在unsigned int中存放这个数据,只有这样才能保证存放的顺序满足TCP/IP的字节顺序要求.很多时候,需要自己编写应用层的协议,字节顺序的概念在这个时候就显得及其的重要了.
下面给出的是在big endian和little endian中相互转换的代码,C语言强大的位操作的能力在这里显示了出来:
/**/
/*
*******************************************************************
created: 2006-9-5
filename: get32put32.cpp
author: 李创
purpose: 在little endian和big ednian之间相互转化数据的演示代码
********************************************************************
*/
#include
<
stdio.h
>
const
unsigned
char
SIZE_OF_UNSIGNEDINT
=
sizeof
(unsigned
int
);
const
unsigned
char
SIZE_OF_UNSIGNEDCHAR
=
sizeof
(unsigned
char
);
void
put_32(unsigned
char
*
cmd, unsigned
int
data)
{
int
i;
for
(i
=
SIZE_OF_UNSIGNEDINT
-
1
; i
>=
0
;
--
i)
{
cmd[i]
=
data
%
256
;
//
或者可以:
//
cmd[i] = data & 0xFF;
data
=
data
>>
8
;
}
}
unsigned
int
get_32(unsigned
char
*
cmd)
{
unsigned
int
ret;
int
i;
for
(ret
=
0
, i
=
SIZE_OF_UNSIGNEDINT
-
1
; i
>=
0
;
--
i)
{
ret
=
ret
<<
8
;
ret
|=
cmd[i];
}
return
ret;
}
int
main(
void
)
{
unsigned
char
cmd[SIZE_OF_UNSIGNEDINT];
unsigned
int
data, ret;
unsigned
char
*
p;
int
i;
data
=
0x12345678
;
printf(
"
data = %x\n
"
, data);
//
以字节为单位打印出数据
p
=
(unsigned
char
*
)(
&
data);
for
(i
=
0
; i
<
SIZE_OF_UNSIGNEDINT;
++
i)
{
printf(
"
%x
"
,
*
p
++
);
}
printf(
"
\n
"
);
//
以相反的顺序存放到cmd之中
put_32(cmd, data);
for
(i
=
0
; i
<
SIZE_OF_UNSIGNEDINT;
++
i)
{
printf(
"
cmd[%d] = %x\n
"
, i, cmd[i]);
}
//
再以相反的顺序保存数据到ret中
//
保存之后的ret数值应该与data相同
ret
=
get_32(cmd);
printf(
"
ret = %x\n
"
, ret);
p
=
(unsigned
char
*
)(
&
ret);
for
(i
=
0
; i
<
SIZE_OF_UNSIGNEDINT;
++
i)
{
printf(
"
%x
"
,
*
p
++
);
}
printf(
"
\n
"
);
return
0
;
}
参考资料:<<C: A Reference Manual>>