大端序和小端序及端序转换(三)

一、大段模式和小端模式
大端模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;
小端模式,是指数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中。
二、为什么会有大小端模式
在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如果将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。例如一个16bit的short型x,在内存中的地址为0x0010,x
的值为0x1122,那么0x11为高字节,0x22为低字节。对于大端模式,就将0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。小端模式,刚好相反。我们常用的X86结构是小端模式,而KEIL C51则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。
三、大小端在内存中的存放方式举例
16bit宽的数0x1234
在Little-endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:
内存地址 0x4001 0x4002
存放内容 0x34 0x12
而在Big-endian模式CPU内存中的存放方式则为:
内存地址 0x4001 0x4002
存放内容 0x12 0x34
32bit宽的数0x12345678
在Little-endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:
内存地址 0x4001 0x4002 0x4003 0x4004
存放内容 0x78 0x56 0x34 0x12
在Big-endian模式CPU内存中的存放方式则为:
内存地址 0x4001 0x4002 0x4003 0x4004
存放内容 0x12 0x34 0x56 0x78
四,有关大小端的习题
题目:在x86系统下,其值为多少?
int main()
{
int a[4]={1,2,3,4};
int ptr1=(int)(&a+1);
int ptr2=(int)((int)a+1);

print ("%x,%x",prt1[-1],*ptr2);

return 0;

}

先说ptr1,我知道 &a是整个数组的首地址,所以&a+1指到了整个数组后面。因为(&a+1)这个地址转换成(int),所以(a&+1)指向了整个数组后一个int型的整数。prt1[-1]就是 (prt1-1),也就是a[3],所以是4。
再说ptr2,a表示数组首元素的首地址,(int)a+1就是把地址a转换int型加1,因为int类型是4个字节存储,(int)a+1就指向a[0]的第二个字节的指针了。转换成(int
)的ptr2就像上图表示的一样指向一个int类型,这就和大端小端存储有关系了。
大端模式
低地址 高地址
a[0] a[1] a[2]
4字节 4字节
大端模式
0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x02 …
小端模式
0x01 0x00 0x00 0x00 0x02 0x00 0x00 0x00 …
在大端模式下读取的是:0x00 0x00 0x01 0x00 也就是0x100
在小端模式下读取的是:0x00 0x00 0x00 0x20 也就是0x2000000
五、编写程序测试机器是大端还是小端模式
方法1(推荐,简单易懂):
/
0 is Big-endian, 1 is Little-endian */
int checkEndian(void)
{
union check
{
int iNum;
char ch;
};
union check c;
c.iNum = 1;
return (1 == c.ch);
}

方法2:
int main(void)
{
short int x;
char x0,x1;
x=0x1122;
x0=((char *)&x)[0]; //低地址单元
x1=((char )&x)[1]; //高地址单元
printf("x0=0x%x,x1=0x%x",x0,x1);// 若x0=0x11,则是大端; 若x0=0x22,则是小端......
return 0;
}
方法3:
typedef unsigned char byte;
// 转换char(视为整数类型)为16进制字符串
void ChtoHex(byte Val, char
dest)
{
// 辗转相除法,倒序看得到结果
byte tmp = Val % 16;
if (tmp >= 0 && tmp <= 9)
{
dest[1] = '0' + tmp;
}
else if (tmp >= 10 && tmp <= 15)
{
dest[1] = 'A' + tmp - 10;
}

tmp = (Val/16) % 16;
if (tmp >= 0 && tmp <= 9)
{
    dest[0] = '0' + tmp;
}
else if (tmp >= 10 && tmp <= 15)
{
    dest[0] = 'A' + tmp - 10;
}
// 设置\0
dest[2] = '\0';

}
// 主函数
void main()
{
int u = 367328153; // 原始数据,8位16进制为15 E4 FB 99
byte a, b, c, d; // u从低地址到高地址的四个字节
// a~d对应的16进制字符串,预留3个字符
char Sa[3], Sb[3], Sc[3], Sd[3];

byte* k = (byte*)&u;
a = k[0];
b = k[1];
c = k[2];
d = k[3];

// 转成16进制字符串
ChtoHex(a, Sa);
ChtoHex(b, Sb);
ChtoHex(c, Sc);
ChtoHex(d, Sd);

printf("%s %s %s %s\n", Sa, Sb, Sc, Sd);

}

posted @   sgggr  阅读(654)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示