对表示一个对象的字节序列排序,有两个通用的规则。有些机器选择在存储器中按照从最低有效字节到最高有效字节的顺序存储对象,而另一些机器按照从最高有效字节到最低有效字节的顺序存储。前一种规则——最低有效字节在最前面的 方式称为小端法(little endian)。大多数源自以前的Digital Equipment公司(现在是Compaq公司的一部分)的机器,以及Intel的机器都采用这种规则。后一种规则(最高有效字节在前面的方式)被称为大端法(big endian)。IBM、Motorola和Sun Microsystems 到大多数机器都采用这种规则。注意我们说的“大多数”。这些规则并没有严格按照企业界限来划分。(摘自《深入理解计算机系统》)
假设变量x的类型为int,位于地址0x100处,有一个十六进制的数0x12345678(高位为0x12,低位为0x78).地址范围为0x100·0x103的字节顺序依赖于机器的类型:
令人吃惊的是在哪种字节顺序是合适的这个问题上,人们表现的非常情绪化。实际上,术语"little endian(小端)"和"big endian(大端)"来自于Jonathan Swift的《格列佛游记》,其中交战的两个派别无法就应该从哪一端——小端还是大端——打开一个半熟的鸡蛋达成一致。就像鸡蛋的问题一样,没有技术原因来选择字节顺序规则,因此争论退化成为关于社会政治论题的口角。对于哪种字节排序的选择是任意的。(摘自深入理解计算机系统)
对于大多数的应用程序员来说,他们机器的字节顺序是完全不可见的。无论哪种机器所编译的程序都会得到同样的结果,不过有时候,字节顺序会成为问题。首先是在不同类型机器之间通过网络传送二进制数据时。一个常见的问题是当小端法机器产生的数据被发送到大端法机器或者反之时,接收程序会发现,字里的字节成了反序的。为了避免这类问题,网络应用程序的代码编写必须遵守已建立的关于字节顺序的规则,以确保发送方机器将它的内部表示转换成网络标准,而接收方机器则将网络标准转换为它的内部表示。(摘自深入理解计算机系统)
今天我来实现一下如何证明自己的机器采用了哪种字节顺序:
第一种方法:
- /* 确定你的电脑是大端字节序还是小端字节序 */
- #include <stdio.h>
- int check1()
- {
- int i = 1; //1在内存中的表示: 0x00000001
- char *pi = (char *)&i; //将int型的地址强制转换为char型
- return *pi == 0; //如果读取到的第一个字节为1,则为小端法,为0,则为大端法
- }
- int main()
- {
- if (check1() == 1)
- printf("big\n");
- else
- printf("little\n");
- return 0;
- }
/* 确定你的电脑是大端字节序还是小端字节序 */
#include <stdio.h>
int check1()
{
int i = 1; //1在内存中的表示: 0x00000001
char *pi = (char *)&i; //将int型的地址强制转换为char型
return *pi == 0; //如果读取到的第一个字节为1,则为小端法,为0,则为大端法
}
int main()
{
if (check1() == 1)
printf("big\n");
else
printf("little\n");
return 0;
}
第二种方法,我们用联合结构解决,其本质差异不大
- /* 确定你的电脑是大端字节序还是小端字节序 */
- #include <stdio.h>
- int check2()
- {
- union test {
- char ch;
- int i;
- }test0;
- test0.i = 1;
- return test0.ch == 0;
- }
- int main()
- {
- if (check1() == 1)
- printf("big\n");
- else
- printf("little\n");
- return 0;
- }
/* 确定你的电脑是大端字节序还是小端字节序 */
#include <stdio.h>
int check2()
{
union test {
char ch;
int i;
}test0;
test0.i = 1;
return test0.ch == 0;
}
int main()
{
if (check1() == 1)
printf("big\n");
else
printf("little\n");
return 0;
}
因为联合结构中的变量共用一块存储空间,所以ch和i拥有同一个地址:
对本例中的联合结构,我们对它求sizeof(test0),会发现它的大小为4,取了int 的大小。
关于union,我们说了,它里边的变量共用一块存储空间,但是它的大小并不总是其中最大的变量所占的空间,还需要考虑对齐!
比如:
union test1 {
char[5];
int i;
}
它的大小就是 8 了!