免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 13974 | 回复: 11
打印 上一主题 下一主题

little endian和big endian的概念解释,判定与用途 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-09-05 21:12 |只看该作者 |倒序浏览
little endian和big endian是表示计算机字节顺序的两种格式,所谓的字节顺序指的是长度跨越多个字节的数据的存放形式.
        假设从地址0x00000000开始的一个字中保存有数据0x1234abcd,那么在两种不同的内存顺序的机器上从字节的角度去看的话分别表示为:
       1)little endian:在内存中的存放顺序是0x00000000-0xcd,0x00000001-0xab,0x00000002-0x34,0x00000003-0x12
       2)big  endian:在内存中的存放顺序是0x00000000-0x12,0x00000001-0x34,0x00000002-0xab,0x00000003-0xcd
       需要特别说明的是,以上假设机器是每个内存单元以8位即一个字节为单位的.
       简单的说,ittle endian把低字节存放在内存的低位;而big endian将低字节存放在内存的高位.
       现在主流的CPU,intel系列的是采用的little endian的格式存放数据,而motorola系列的CPU采用的是big endian.
      
       以下是判断字节存储顺序的可移植的C语言代码:

  1. /********************************************************************
  2.         created:        2006-9-5
  3.         filename:         test.cpp
  4.         author:                李创
  5.        
  6.         purpose:        可移植的用于判断存储格式是
  7.                 little endian还是big ednian的C代码
  8.                 取自<<C: A Reference Manual>>
  9. *********************************************************************/

  10. #include <stdio.h>

  11. union
  12. {
  13.         long Long;
  14.         char Char[sizeof(long)];
  15. }u;

  16. int main()
  17. {       
  18.         u.Long = 1;
  19.        
  20.         if (u.Char[0] == 1)       
  21.         {
  22.                 printf("Little Endian!\n");
  23.         }
  24.         else if (u.Char[sizeof(long) - 1] == 1)
  25.         {
  26.                 printf("Big Endian!\n");
  27.         }
  28.         else
  29.         {
  30.                 printf("Unknown Addressing!\n");
  31.         }

  32.     printf("Now, Let's look at every byte in the memory!\n");
  33.     for (int i = 0; i < sizeof(long); ++i)
  34.     {
  35.         printf("[%x] = %x\n", &u.Char[i], u.Char[i]);
  36.     }

  37.         return 0;
  38. }
复制代码


很多人认为掌握这个知识是不必要,其实不然.在网络编程中,TCP/IP统一采用big endian方式传送数据,也就是说,假设现在是在一个字节顺序是little endian的机器上传送数据,要求传送的数据是0XCEFABOBO,那么你就要以0XBOBOFACE的顺序在unsigned int中存放这个数据,只有这样才能保证存放的顺序满足TCP/IP的字节顺序要求.很多时候,需要自己编写应用层的协议,字节顺序的概念在这个时候就显得及其的重要了.
       下面给出的是在big endian和little endian中相互转换的代码,C语言强大的位操作的能力在这里显示了出来:


  1. /********************************************************************
  2.         created:        2006-9-5
  3.         filename:         get32put32.cpp
  4.         author:                李创
  5.        
  6.         purpose:        在little endian和big ednian之间相互转化数据的演示代码

  7. *********************************************************************/


  8. #include <stdio.h>

  9. const unsigned char SIZE_OF_UNSIGNEDINT  = sizeof(unsigned int);
  10. const unsigned char SIZE_OF_UNSIGNEDCHAR = sizeof(unsigned char);

  11. void put_32(unsigned char *cmd, unsigned int data)
  12. {
  13.     int i;
  14.     for (i = SIZE_OF_UNSIGNEDINT - 1; i >= 0; --i)
  15.     {
  16.         cmd[i] = data % 256;
  17.         // 或者可以:
  18.         //cmd[i] = data & 0xFF;
  19.         data = data >> 8;
  20.     }
  21. }

  22. unsigned int get_32(unsigned char *cmd)
  23. {
  24.     unsigned int  ret;
  25.     int i;

  26.     for (ret = 0, i = SIZE_OF_UNSIGNEDINT - 1; i >= 0; --i)
  27.     {
  28.         ret  = ret << 8;
  29.         ret |= cmd[i];        
  30.     }
  31.        
  32.     return ret;
  33. }

  34. int main(void)
  35. {
  36.     unsigned char cmd[SIZE_OF_UNSIGNEDINT];
  37.     unsigned int data, ret;
  38.     unsigned char *p;
  39.     int i;

  40.     data = 0x12345678;
  41.     printf("data = %x\n", data);
  42.     // 以字节为单位打印出数据
  43.     p = (unsigned char*)(&data);
  44.     for (i = 0; i < SIZE_OF_UNSIGNEDINT; ++i)
  45.     {
  46.         printf("%x", *p++);
  47.     }
  48.     printf("\n");

  49.     // 以相反的顺序存放到cmd之中
  50.     put_32(cmd, data);
  51.     for (i = 0; i < SIZE_OF_UNSIGNEDINT; ++i)
  52.     {
  53.         printf("cmd[%d] = %x\n", i, cmd[i]);
  54.     }

  55.     // 再以相反的顺序保存数据到ret中
  56.     // 保存之后的ret数值应该与data相同
  57.     ret = get_32(cmd);
  58.     printf("ret = %x\n", ret);
  59.     p = (unsigned char*)(&ret);
  60.     for (i = 0; i < SIZE_OF_UNSIGNEDINT; ++i)
  61.     {
  62.         printf("%x", *p++);
  63.     }
  64.     printf("\n");

  65.     return 0;
  66. }
复制代码


参考资料:<<C: A Reference Manual>>

[ 本帖最后由 converse 于 2006-10-30 17:30 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2006-09-05 21:40 |只看该作者
ittle endian:0xcdab3412,即0x00000000-0xcd,0x00000001-0xab,0x00000002-0x34,0x00000003-0x12

little endian把低位存放到高位

上面的说反了吧.little endian应当是
0x00000000-0x12
0x00000001-0x34
....
这样的吧.

little endian把低字节存放到低地址,把高字节放到高地址.
数据0xcdab3412从左到右,由高字节到低字节,由高地址到低地址.

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>

  4. int main()
  5. {
  6.     int value = 0x12345678;

  7.     union ValueT
  8.     {
  9.         int value;
  10.         char data[4];
  11.     } a;
  12.     a.value = 0x12345678;
  13.     printf("value is 0x%x\n", a.value);
  14.     printf("address is %p, 0x%x\n",&a.data[0], a.data[0]);
  15.     printf("address is %p, 0x%x\n",&a.data[1], a.data[1]);
  16.     printf("address is %p, 0x%x\n",&a.data[2],  a.data[2]);
  17.     printf("address is %p, 0x%x\n", &a.data[3], a.data[3]);

  18.     exit(EXIT_SUCCESS);
  19. }
复制代码

value is 0x12345678
address is 0xbffffa0c, 0x78
address is 0xbffffa0d, 0x56
address is 0xbffffa0e, 0x34
address is 0xbffffa0f, 0x12

[ 本帖最后由 coldwarm 于 2006-9-5 21:56 编辑 ]

论坛徽章:
0
3 [报告]
发表于 2006-09-05 22:21 |只看该作者
原帖由 coldwarm 于 2006-9-5 21:40 发表
ittle endian:0xcdab3412,即0x00000000-0xcd,0x00000001-0xab,0x00000002-0x34,0x00000003-0x12

little endian把低位存放到高位

上面的说反了吧.little endian应当是
0x00000000-0x12
0x00000001-0x34
. ...



感谢指出错误,我的描述有问题,应该是这样:

       假设从地址0x00000000开始的一个字中保存有数据0x1234abcd,那么在两种不同的内存顺序的机器上从字节的角度去看的话分别表示为:
       1)little endian:在内存中的存放顺序是0x00000000-0xcd,0x00000001-0xab,0x00000002-0x34,0x00000003-0x12
       2)big  endian:在内存中的存放顺序是0x00000000-0x12,0x00000001-0x34,0x00000002-0xab,0x00000003-0xcd

论坛徽章:
0
4 [报告]
发表于 2006-09-06 09:22 |只看该作者
sun的xdr对字节的转换提供了一整套的函数

论坛徽章:
0
5 [报告]
发表于 2006-09-06 09:30 |只看该作者
socket 中就有现成的,不需要自己写,也不需要什么 xdr
       #include <arpa/inet.h>

       uint32_t htonl(uint32_t hostlong);

       uint16_t htons(uint16_t hostshort);

       uint32_t ntohl(uint32_t netlong);

       uint16_t ntohs(uint16_t netshort);

论坛徽章:
0
6 [报告]
发表于 2006-09-09 10:41 |只看该作者
hton等函数适用性不是太强l
#include <rpc/xdr.h>

xdr_array(
        XDR *xdrs,
        char **arrp,
        u_int *sizep,
        u_int *maxsize,
        u_int *elsize,
        xdrproc_t elproc );

xdr_bool(
        XDR *xdrs,
        bool_t bp );

xdr_bytes(
        XDR *xdrs,
        char **sp,
        u_int *sizep,
        u_int maxsize );

xdr_char(
        XDR *xdrs,
        char*cp );

void xdr_destroy(
        XDR *xdrs );

xdr_double(
        XDR *xdrs,
        double *dp );

xdr_enum(
        XDR *xdrs,
        enum_t *ep );

xdr_float(
        XDR *xdrs,
        float *fp );

void xdr_free(
        xdrproc_t proc,
        char *objp );

u_int xdr_getpos(
        XDR *xdrs );

xdr_hyper(
        XDR *xdrs,
        longlong_t *hp );

long *xdr_inline(
        XDR *xdrs,
        int len );

xdr_int(
        XDR *xdrs,
        int *ip );

xdr_long(
        XDR *xdrs,
        long *lp );

xdr_longlong_t(
        XDR *xdrs,
        longlong_t *hp );

xdr_opaque(
        XDR *xdrs,
        char *cp,
        u_int cnt );

xdr_pmap(
        XDR *xdrs,
        struct pmap *regs );

xdr_pmaplist(
        XDR *xdrs,
        struct pmaplist **rp );

xdr_pointer(
        XDR *xdrs,
        char **objpp,
        u_int objsize,
        xdrproc_t xdrobj );

xdr_reference(
        XDR *xdrs,
        char **pp,
        u_int size,
        xdrproc_t proc );

xdr_setpos(
        XDR *xdrs,
        u_int pos );

xdr_short(
        XDR *xdrs,
        short *sp );

xdr_string(
        XDR *xdrs,
        char **sp,
        u_int maxsize );

xdr_u_char(
        XDR *xdrs,
        unsigned char *ucp );

xdr_u_hyper(
        XDR *xdrs,
        u_longlong_t *uhp );

xdr_u_int(
        XDR *xdrs,
        unsigned *up );

xdr_u_long(
        XDR *xdrs,
        unsigned long *ulp );

xdr_u_longlong_t(
        XDR *xdrs,
        u_longlong_t *uhp );

xdr_u_short(
        XDR *xdrs,
        unsigned short *usp );

xdr_union(
        XDR *xdrs,
        int *dscmp,
        char *unp,
        struct xdr_discrim *choices,
        bool_t (*defaultarm) (void) );

xdr_vector(
        XDR *xdrs,
        char *arrp,
        u_int size,
        u_int elsize,
        xdrproc_t elproc );

xdr_void(
        void );

xdr_wrapstring(
        XDR *xdrs,
        char **sp );

void xdrmem_create(
        XDR *xdrs,
        char *addr,
        u_int size,
        enum xdr_op op );

void xdrrec_create(
        XDR *xdrs,
        u_int sendsize,
        u_int recvsize,
        char *handle,
        int (*readit) (void),
        int (*writeit) (void) );
这个基本上涵盖了各种类型

论坛徽章:
0
7 [报告]
发表于 2006-09-15 11:58 |只看该作者
代码应该是:


  1. if  (u.Char[ 0 ]  ==   1 )   
  2.       {
  3.         printf( " [color=Red]Big[/color] Endian!\n " );
  4.     }
  5.      else   if  (u.Char[ sizeof ( long )  -   1 ]  ==   1 )
  6.       {
  7.         printf( " [color=Red]little[/color] Endian!\n " );
  8.     }

复制代码

[ 本帖最后由 snowoak 于 2006-9-15 12:11 编辑 ]

论坛徽章:
0
8 [报告]
发表于 2006-09-15 12:10 |只看该作者
原帖由 snowoak 于 2006-9-15 11:58 发表
还是有问题吧,应该是:
little endian:
0x00000000:0x12
……
0x00000003:0xcd

big endian:
0x00000000:0xcd
……
0x00000003:0x12




是你自己的那个有问题,同意lz的说法

论坛徽章:
0
9 [报告]
发表于 2006-09-15 12:17 |只看该作者
原帖由 sway2004009 于 2006-9-15 12:10 发表


是你自己的那个有问题,同意lz的说法

呵呵,我知道是我的问题了:)

论坛徽章:
0
10 [报告]
发表于 2006-10-30 17:26 |只看该作者
原帖由 converse 于 2006-9-5 21:12 发表
简单的说,little endian把低位存放到高位,而big endian把低位存放到低位.


这个总结错了吧,应该是
little endian把低字节存放在内存的低位;而big endian将低字节存放在内存的高位。

0x1234adcd中,0xcd算是低字节
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP