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


    一、大段模式和小端模式
    大端模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;
    小端模式,是指数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中。
    二、为什么会有大小端模式
    在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为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);
    

    }

  • 相关阅读:
    【alpha】Scrum站立会议第2次....10.17
    【alpha】Scrum站立会议第1次····10.16
    【week4】技术随笔psp
    【week4】课堂Scrum站立会议
    【week3】psp (技术随笔)
    【week3】四则运算 单元测试
    【week3】词频统计 单元测试
    Oracle Split字符串

    指针函数与指针数组
  • 原文地址:https://www.cnblogs.com/sggggr/p/16381890.html
Copyright © 2020-2023  润新知