重新审视大端和小端

本文详细解释了大端和小端存储方式的历史由来及技术原理,并通过示例直观展示了这两种字节序的区别。此外,还提供了一段用于检测计算机系统采用何种字节序的C语言代码。

以前汇编课上讲过,但是我发现还不够。。。下面全面介绍了大端和小端。

大端和小端的历史:

一般吃鸡蛋都是打破鸡蛋大的一端再吃,但是有一次,一个国家的国王打鸡蛋时把手指弄破了,后来,他下令:以后打鸡蛋都从小端开始打。

为了讽刺这件事,就有了大端和小端的概念。

如果一个对象跨越多字节连续存储,则最小的地址就是对象的地址。

比如一个int,在32位和64位机器中都是4字节,如果对象地址为0x100,则整个int占据0x100,0x101,0x102,0x103.

我们都知道&符号,假如int x; &x就为x的地址,即0x100.

[31,30,29,.....1,0]为有效位数,最高有效位为31,最低有效位为0。

小端法:最低有效位存在最前面。

0x100 0x101

---------------------------------------------------------------------------------------------------

| 7,6,5,4,3,2,1,0 |15,14,13,12,11,10,9,8 | ....

----------------------------------------------------------------------------------------------------

大端法:最高有效位存在最前面。

0x100 0x101

---------------------------------------------------------------------------------------------------

|31,30,29,28,27,26,25,24| 23,22,21,20,19,18,17,16| ....

----------------------------------------------------------------------------------------------------

这两张图的对比就很明显的看出区别,就比如int x=2; 转换为16进制为0x00 00 00 02;

小端的存放顺序为:

0x100 0x101 0x102 0x103

----------------------------------------------------

|02 | 00 | 00 | 00 |

----------------------------------------------------

上面已经说过&x取得的是0x100,一般情况下程序员是看不出字节顺序的区别的。

在linux32中,结果为小端存储。

以下是检测大端小端的代码,

记住*****:我们要检测大端小端,必须要把他转化为unsigned char * ch才可以。因为这个ch[i]是一个字节。

--------------------------------------------------------------------------------------------------------------------

#include<stdio.h> typedef unsigned char *byte_pointer; void show_bytes(byte_pointer start,int len) { int i; for(i=0;i<len;i++) printf(" %.2x",start[i]); printf("/n"); } void show_int(int x) { show_bytes((byte_pointer)&x,sizeof(int)); } void show_float(float x) { show_bytes((byte_pointer)&x,sizeof(float)); } void test() { int val=0x87654321; byte_pointer valp=(byte_pointer)&val; show_bytes(valp,4); printf("/n"); int val1=3510593; float val2=3510593.0; show_int(val1); show_float(val2); } int main() { test(); return 0; }

int x=0x12345678;

unsigned char *val=(unsigned char *)&x; //x的地址。

val[0] 为val的地址只指向的字节。

请你实现一个基于栈(先进后出)的虚拟机,执行输入的指令cmds后返回从栈底到栈顶的数据。 cmds是16进制字符串表示的字节流,字符为[0-9A-F],字母为大写,每两个字符表示1个字节。内容是一串紧密排列的变长指令,每条指令格式为 [Op][Body]: Op 为指令码,固定为2个字节; Body 为操作内容,长度含义由 Op 决定。 指令 Op Body 含义 PUSH 0xC001 长度 4 字节,表示1个非负整数 将Body中的数字压栈 POP 0xC002 长度 0 字节 从栈中弹出1个数字并丢弃;若栈为空,则忽略该指令 ADD 0xC011 长度 4 字节,表示1个非负整数 从栈中弹出1个数字A(若栈为空,则A=0), 与Body中的数字B相加:A + B,将运算结果压栈 SUB 0xC012 长度 4 字节,表示1个非负整数 从栈中弹出1个数字A(若栈为空,则A=0), 与Body中的数字B相减:A - B ,将运算结果压栈 JGT 0xC021 长度 2 字节,表示1个非负整数 从栈中弹出1个数字 A (若栈为空,则 A=0), 再从栈中弹出1个数字 B (若栈为空,则B=0) 进行大小比较:若A >= B,则跳转到字节流中从首字节开始、偏移量(单位:字节)为Body值的位置;否则,顺序执行下一条指令 从 cmds 首条指令开始执行;没触发跳转条件时,执行下一条指令。 输入 1 <= cmds.length <= 5000,栈最大深度不超过 64; Body 中的数字的范围 [0, 2^32) 输入保证: 跳转指令不会导致死循环,跳转的指令位置是合法指令。 用例保证:计算过程结果的范围:[-2^40, 2^40] 字节流为网络字节序(即大端序),大端序的高位字节在低地址,小端序的高位字节在高地址,如:数字 65538,其4字节表示的大端序内容为 00010002,小端序内容为 02000100 输出 一个序列,表示从栈底到栈顶的数据 样例1 复制输入: "C001FFFF0001C0110000FFFFC00100000000C012FABC0000C00100000003C002" 复制输出: [4294967296, -4206624768] 解释: 指令执行顺序如下: 偏移量 指令 Body 执行后的栈数据(右边栈顶) 0 PUSH 0xFFFF0001 [4294901761] 6 ADD 0x0000FFFF [4294967296] 12 PUSH 0x00000000 [4294967296, 0] 18 SUB 0xFABC0000 [4294967296, -4206624768] 24 PUSH 0x00000003 [4294967296, -4206624768, 3] 30 POP - [4294967296, -4206624768] 注:偏移量单位为字节 输入的字符串转换为字节流为 arr[] = [0xC0, 0x01, 0xFF, 0xFF, 0x00, 0x01, 0xC0, 0x11, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x01, ...],以ADD命令为例:偏移量为6,该命令在arr中的起始位置为下标6,完整命令为 [0xC0, 0x11, 0x00, 0x00, 0xFF, 0xFF]。 样例2
最新发布
11-26
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值