2007年8月5日星期日

Big Endian 和 Little Endian

最近在工作中遇到一些问题,我用 Java 按照特定的媒体格式在硬盘上生成一个二进制文件,然后该文件由 VC++ 写的播放器播放。结果播放器读取的数据和我在同样位置写入的不符,遂引出了Big Endian 和 Little Endian 的概念(“Endian”应该怎么发音?我也不知道,先把它读作”安迪安”,有谁知道告诉我^_^),最终我写了一个转换类在写文件时将 Big Endian 转换成 Little Endian (见 2)。

以下对于 Big Endian 和 Little Endian 的介绍转自博客《七里香》(http://ericbin.blogchina.com)

谈 到字节序的问题,必然牵涉到两大CPU派系。那就是Motorola的PowerPC系列CPU和Intel的x86系列CPU。PowerPC系列采用 big endian方式存储数据,而x86系列则采用little endian方式存储数据。那么究竟什么是big endian,什么又是little endian呢?

其实big endian是指低地址存放最高有效字节(MSB),而little endian则是低地址存放最低有效字节(LSB)。

用文字说明可能比较抽象,下面用图像加以说明。比如数字0x12345678在两种不同字节序CPU中的存储顺序如下所示:

Big Endian

低地址 高地址

----------------------------------------->

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| 12 | 34 | 56 | 78 |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Little Endian

低地址 高地址
----------------------------------------->

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| 78 | 56 | 34 | 12 |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

从 上面两图可以看出,采用big endian方式存储数据是符合我们人类的思维习惯的。而little endian,!@#$%^&*,见鬼去吧 -_-||| 为什么要注意字节序的问题呢?你可能这么问。当然,如果你写的程序只在单机环境下面运行,并且不和别人的程序打交道,那么你完全可以忽略字节序的存在。但 是,如果你的程序要跟别人的程序产生交互呢?在这里我想说说两种语言。C/C++语言编写的程序里数据存储顺序是跟编译平台所在的CPU相关的,而 JAVA编写的程序则唯一采用big endian方式来存储数据。试想,如果你用C/C++语言在x86平台下编写的程序跟别人的JAVA程序互通时会产生什么结果?就拿上面的 0x12345678来说,你的程序传递给别人的一个数据,将指向0x12345678的指针传给了JAVA程序,由于JAVA采取big endian方式存储数据,很自然的它会将你的数据翻译为0x78563412。什么?竟然变成另外一个数字了?是的,就是这种后果。因此,在你的C程序 传给JAVA程序之前有必要进行字节序的转换工作。 无独有偶,所有网络协议也都是采用big endian的方式来传输数据的。所以有时我们也会把big endian方式称之为网络字节序。当两台采用不同字节序的主机通信时,在发送数据之前都必须经过字节序的转换成为网络字节序后再进行传输。ANSI C中提供了下面四个转换字节序的宏。


htonl Convert a long from host to network byte ordering.
htons Convert a short from host to network byte ordering.
ntohl
Convert a long from network to host byte ordering.
ntohs Convert a short from network to host byte ordering.

没有评论: