大小端问题

对于跨越多字节的程序对象,我们必须建立两个规则:

①这个对象的地址是什么?

②内存中如何排列这些字节?

几乎在所有的机器上,多字节对象都被存储为连续的字节序列,对象的地址为所使用字节中最小的地址。

例如,假设一个类型为int的变量x的地址为0x100,也就是说,地址表达式&x的值为0x100。那么,(假设数据类型int为32位表示)x的4个字节将被存储在内存的0x100、0x101、0x102和0x103位置。

排列表示一个对象的字节有两个通用的规则。考虑一个w位的整数,其表示为[xw-1,xw-2, ..., x1, x0]其中xw-1是最高有效位,而x0是最低有效位。假设w是8的倍数,这些位就能被分组成为字节,其中最高有效位包含位[xw-1,xw-2,...,xw-8],而最低有效字节包含位[x7,x6,...,x0],其他字节包含中间的位。某些机器选择在内存中按照从最低有效字节到最高有效字节的顺序存储对象,而另一些机器则按照从最高有效
字节到最低有效字节的顺序存储。前一种规则,最低有效字节在最前面的方式——称之为小端法(little endian)。后一种规则。最高有效字节在最前面的方式——称为大端法(big endian)
假设变量x的类型为int,位于地址0x100处,他的16进制值为,0x01234567。地址范围,0x100~0x103的字节顺序依赖于机器的类型:

注意,在字0x01234567中,最高字节的十六进制为0x01,而最低位字节值为0x67。
大多数Intel兼容机都只用小端模式。另一方面,IBM和Oracle。的大多数机器则是按大端模式操作。注意我们说的是大多数,这些规则并没有严格按照企业界限来划分。比如IBM和Oracle制造的个人计算机使用的是Intel兼容的处理器,因此使用小端法。许多比较新的微处理器是双端法(bi-endian)。也就是说可以把它们配置成作为大端或者小端的机器运行。然而,实际情况是一旦选择了特定操作系统,那么字节顺序也就固定下来,比如许多移动电话的ARM处理器,其硬件可以按小端或大端两种模式操作,但是这些芯片上最常见的两种操作系统,Android(来自Google)和iOS(来自Apple)——却只能运行于小端模式
示例代码(环境为Windows下的Ubantu)
#include<stdio.h>
#include<string.h>


typedef unsigned char* byte_pointer;


void show_bytes(byte_pointer start, size_t len)
{
	size_t i;
	for(i=0; i<len; ++i)
		printf(" %.2x", start[i]);//C格式化命令“%。2x”表示必须用至少两个数字的十六进制的格式输出
	printf("\n");
}
int main()
{
	short sx = -12345;//其在内存存储的二进制是 1100 1111 1100 0111,十六进制为0xcfc7
	unsigned short usx = sx;//隐式转换,将无符号转为有符号,即usx直接将0xcfc7看成一个无符号数
	int x = sx;//short转int,其在内存存储的二进制反码是1111 1111 1111 1111 1100 1111 1100 0111(高位补16个符号位),十六进制为0xffffcfc7
	unsigned ux = usx;//int转unsigned short,即ux直接将0xcfc7看为一个无符号数,但是unsigned int 比unsigned short多16位,则多的161位补零(补充符号位),即ux在在内存中的十六进制为0x0000cfc7
	
	printf("sx = %d:\t", sx);
	show_bytes((byte_pointer) &sx, sizeof(short));
	printf("usx = %u:\t", usx);
	show_bytes((byte_pointer) &usx, sizeof(unsigned short));
	printf("x = %d:\t", x);
	show_bytes((byte_pointer) &x, sizeof(int));
	printf("ux = %u:\t", ux);
	show_bytes((byte_pointer) &ux, sizeof(unsigned));
	return 0;

}

  

 运行结果
 

 可以看到,Ubantu环境使用小端法


”端“的起源
我下面要告诉你的是,这两大强国在过去三十六个月里一直在苦战。战争开始是由于以下的原因:我们大家都认为,吃鸡蛋前,原始的方法是打破鸡蛋较大的一端。可是当今皇帝的祖父小时候吃鸡蛋,一次按古法打鸡蛋时碰巧将一个手指弄破了,因此他的父亲,当时的皇帝,就下了一道敕令,命令全体臣民吃鸡蛋时打破鸡蛋较小的一端,违令者重罚。老百姓们对这项命令极为反感。历史告诉我们,由此曾发生过六次叛乱,其中一个皇帝送了命,另一个丢了王位。这些叛乱大多都是由不来夫斯库国的国王大臣们煽动起来的。叛乱平息后,流亡的人总是逃到那个帝国去寻救避难。据估计,先后几次有一万一千人情愿受死也不肯去打破鸡蛋较小的一端。关于这一争端,曾出版过几百本大部著作,不过大端派的书一直是受禁的,法律也规定该派的任何人不得做官。
——Jonathan Swift的《格列佛游记》第一卷第四章
 
posted @ 2019-04-08 22:49  C_hp  阅读(634)  评论(0编辑  收藏  举报