目录
一、什么是大小端
假如定义一个 int 类型的变量 a,让 a = 12345678(十六进制)
我们知道,数据在计算机中存储的单位是字节,1 Byte = 8 Bit = 2 个十六进制位。
’
而这四个字节在内存中与两种不同的存储方式
什么是大小端:
大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;
小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位,,保存在内存的高地址中。
为什么会有大小端:
至于为什么要区分大小端,这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为 8bit。但是在C语言中除了 8bit 的 char 之外,还有 16bit 的 shor t型,32 bit 的 long 型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。例如一个16bit的short型x,在内存中的地址为0x0010,x的值为0x1122,那么0x11为高字节,0x22为低字节。对于 大端模式,就将0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。小端模式,刚好相反。我们常用的X86结构是小端模式,而KEIL C51则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以随时在程序中(在ARM Cortex 系列使用REV、REV16、REVSH指令)进行大小端的切换。
二、如何确定大小端
对于我们经常使用的x86架构的pc机来说,数据在内存中的存储方式为小端存储。
两种不同的求大小端的方式
//方法一
#include <stdio.h>
int check_sys()
{
int i = 1;
//转换为二进制补码:00 00 00 01
//小端:01 00 00 00
//大端:00 00 00 01
return (*(char*)&i);
//取出 i 的首字节数据
//小端:01 -> 1
//大端:00 -> 0
}
int main()
{
int ret = check_sys();
if (ret == 1)
{
printf("小端\n");
}
else
{
printf("大端\n");
}
return 0;
}
//方法二
#include <stdio.h>
int check_sys()
{
union//共用体共用一段内存
{
int i;
char c;
}un;
un.i = 1;
//小端:10 00 00 00
//大端:00 00 00 01
return un.c;
//小端:10 -> 1
//大端:00 -> 0
}
int main()
{
int ret = check_sys();
if (ret == 1)
{
printf("小端\n");
}
else
{
printf("大端\n");
}
return 0;
}
常见的求大小端错误的方式:
//强制类型转换
#include <stdio.h>
int main()
{
int a = 1;
char b;
b = (char)a;
//a的补码:00 00 00 01 -> 1
//强制类型转换时发生数据截断
//此时 b 的补码:01 -> 1
printf("b = %d\n", b);
//无论大小端,结果都是1
return 0;
}
//移位
#include <stdio.h>
int main()
{
int a, b;
a = 1;
//a 的补码:0000 0000 0000 0000 0000 0000 0000 0001 -> 1
b = a >> 1;
//移位后 b 的补码:0000 0000 0000 0000 0000 0000 0000 0000 -> 0
printf("b = %d\n", b);
//无论大小端,结果都是0
return 0;
}
//位于
#include <stdio.h>
int main()
{
int a = 1;
//a 的补码:0000 0000 0000 0000 0000 0000 0000 0001
int b = a & 0xff;
// 0000 0000 0000 0000 0000 0000 0000 0001
// &1111 1111 1111 1111 1111 1111 1111 1111
// =0000 0000 0000 0000 0000 0000 0000 0001 -> 1
//char b = a & 0xff 也是同理
printf("b = %d\n", b);
//无论大小端,结果都是1
return 0;
}
总结:
对于取地址(指针)和联合体类型的操作都是基于内存层次的运算,这两种方法可以判断数据在内存上的存储方式。而对于强制类型转换和位于、移位的操作都是基于二进制补码层次的运算,这是高于内存层次的运算,也就是说将内存里面存放的数据拿出来再进行的运算,此时无法判断数据在内存中存储的方式。
本文含有隐藏内容,请 开通VIP 后查看