糖炒栗子

cheap to talk,show muscle would be better...

导航

大端模式和小端模式 big-endian和little-endian

一、大端和小端的问题:

      对于整型、长整型等数据类型,Big endian 认为第 一个字节是最高位字节(按照从低地址到高地址的顺序存放数据的高位字节到低位字节);而
      Little endian 则 相反,它认为第一个字节是最低位字节(按照从低地址到高地址的顺序存放数据的低位字节到高位字节)。
      例如,假设从内存地址 0x0000 开始有以下数据:
      0x0000          0x0001         0x0002         0x0003
      0x12            0x34           0xab           0xcd
      如果我们去读取一个地址为 0x0000 的四个字节变量,若字节序为big-endian,则读出结果为0x1234abcd;
      若字节序位little-endian,则读出结果为0xcdab3412。
      如果我们将0x1234abcd 写入到以 0x0000 开始的内存中,则Little endian 和 Big endian 模式的存放结果如下:
      地址         0x0000       0x0001       0x0002       0x0003
      big-endian     0x12           0x34            0xab            0xcd
      little-endian 0xcd           0xab            0x34            0x12
      一般来说,x86 系列 CPU 都是 little-endian 的字节序,PowerPC 通常是 Big endian,还有的CPU
      能通过跳线来设置 CPU 工作于 Little endian 还是 Big endian 模式。
      对于0x12345678的存储:
      小端模式:(从低字节到高字节)
      地位地址 0x78 0x56 0x34 0x12 高位地址
      大端模式:(从高字节到低字节)
      地位地址 0x12 0x34 0x56 0x78 高位地址
      main()
      {
      char *sz = "0123456789";
      int *p = (int*)sz;
      printf("%x\n",*++p);
      }
      字符'0'对应的十六进制是0x30,请问程序输出是多少?
      主要考察的目的是大端和小端的问题。
      对于intel架构的cpu,是小端模式,如果出现跨多个自己的数据类型,如int,long等,低地址存储数据的低位,高地址存储数据的高位。
      地址从@0开始,那么sz在内存的存储为
      @0 @1 @2 @3 @4 @5 @6 @7 @8 @9
      0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39
      当你把char*强制类型转化成int*后,因为int占四个字节,那么p指向@0,并且*p占有的地址是@0@1@2@3,打印的时候
      先进行++p操作,那么p指向@4,此时*p占有的地址是@4@5@6@7,根据上面地地址存地位,高地址存高位的解释,那么
      *p应该等于0x37363534

          int a=0x12345678;
          char *p=(char*)(&a);
          printf("%x\n",*(p+1));
      例如对于0x12345678,大部分Unix机器和网络是这样0x12,0x34,0x56,0x78存储的,这种方式成为big-endian
      intel处理器列如0x78 0x56 0x34 0x12这样来存储的,成为小尾little-endian
      题目中的p指向0x78,加1后指向0x56
      二、大端小端转换方法:
        Big-Endian转换成Little-Endian如下:
      #define BigtoLittle16(A)                 ((((uint16)(A) & 0xff00) >> 8) |
\
      (((uint16)(A) & 0x00ff) << 8))
      #define BigtoLittle32(A)                 ((((uint32)(A) & 0xff000000) >>
      24) | \
      (((uint32)(A) & 0x00ff0000) >> 8) | \
      (((uint32)(A) & 0x0000ff00) << 8) | \
      (((uint32)(A) & 0x000000ff) << 24))
      三、大端小端检测方法:
        如何检查处理器是big-endian还是little-endian?
      C程序:
          int i=1;  
          char *p=(char *)&i;  
          if(*p==1)    
                printf("Little Endian");
          else
                printf("Big Endian");
         
      大小端存储问题,如果小端方式中(i占至少两个字节的长度)则i所分配的内存最小地址那个字节中就存着1,其他字节是0.大端的话则1在i的最高地址字节处存放,char是一个字节,所以强制将char型量p指向i则p指向的一定是i的最低地址,那么就可以判断p中的值是不是1来确定是不是小端。
        联合体union的存放顺序是所有成员都从低地址开始存放,利用该特性就可以轻松地获得了CPU对内存采用Little-endian还是Big-endian模式读写。
      int checkCPUendian()
      {
      union
      {
          unsigned int a;
          unsigned char b;
      }c;
      c.a = 1;
      return (c.b == 1);
      }
      /*return 1 : little-endian, return 0:big-endian*/

posted on 2012-06-04 14:36  糖炒栗子  阅读(245)  评论(0)    收藏  举报