关于endian

关于endian “endian”这个词出自《格列佛游记》。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开,由此曾发生过六次叛乱,其中一个皇帝送了命,另一个丢了王位。

我们一般将endian翻译成“字节序”,将bigendian和littleend

大家好,欢迎来到IT知识分享网。关于endian

关于endian这个词Pconline上的解释如下:

“endian”这个词出自《格列佛游记》。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开,由此曾发生过六次叛乱,其中一个皇帝送了命,另一个丢了王位。

我们一般将endian翻译成“字节序”,将big endian和little endian称作“大尾”和“小尾”。

还挺有趣的,不是吗?这些黑客们又同时是奇客(geek),总喜欢在学问中搞出些小小的“玩笑”来调剂自己的生活,并乐在其中,它和做学问的时侯的严谨完美的结合在黑客身上,还显得如此的协调!

初次遇到关于endian的问题是在学习网络编程的时侯,因为端口号要进行字节序列的转换,所以那本书简单地解释了endian,并对big endian和little endian做如下解释:

  • Big endian: 当存储一个超过一个字节的数据类型时,将其中的高位放在低地址的地方,低位放在高地址的地方。
  • Little endian: 于Big endian恰恰相反。

那个时侯我确实也是明白了,自以为知之也。

不久前在Linux的内核里面再次遇到关于endian的问题,茫然:

File: include/linux/ip.h

 82 struct iphdr {
 83 #if defined(__LITTLE_ENDIAN_BITFIELD)
 84         __u8    ihl:4,
 85                 version:4;
 86 #elif defined (__BIG_ENDIAN_BITFIELD)
 87         __u8    version:4,
 88                 ihl:4;
 89 #else
 90 #error  “Please fix <asm/byteorder.h>”
 91 #endif
 92         __u8    tos;
 93         __be16  tot_len;
 94         __be16  id;
 95         __be16  frag_off;
 96         __u8    ttl;
 97         __u8    protocol;
 98         __u16   check;
 99         __be32  saddr;
100         __be32  daddr;
101         /*The options start here. */
102 };

当看到83-91行的代码的时侯,再次陷入到了endian的泥沼之中,难道在小于自己单位的bit之中也存在endian的问题?

Google到了一些资料,看了之后只发觉自己更加的模糊,似乎有些文章的作者自己也不是很明白,看来这个工作之能靠自己测试了。经过几个程序的简单测试之后,终于找到了一个简单的endian分析方法,先描述如下(希望我的晦涩的言语您能读懂):

当需要用多个字节来描述一个数据类型,或者是一个数据结构中包含多个字段时,各个字段和存储区块中的地址的映射关系如下:

  • big endian: 存储的区块按照地址从低到高的顺序以字节为单位从左到右排列,划分字段的时侯,从左到右依次划分。
  • little endian: 存储的区块按照地址从高到低的顺序以字节为单位从左到右排列,划分的时侯,从右到左依次划分。

很有可能大家不知我所云,现在简单的给大家举几个简单的例子:

u_int16_t x = 0x1;
u_int8_t xx[2];
memcpy(xx, x);

在上面的代码中,最终xx[0]和xx[1]都是什么呢?

答案是不固定的,如果是在big endian的计算机上:

应用第一条规则,从xx中从取出两个字节x[0], x[1]。我们知道x[1]的地址肯定比x[0]高,所以排列如下:

x[0] x[1]
———
15 …  0
———
00    01

很明显x[0] == 0, x[1] == 1.

如果是little endian的计算机:

应用第二条规则:

x[1] x[0]
———
15 …  0
———
 00   01

结果为x[0] == 1, x[1] == 0.

仔细看看结论是不是和在文章开始的判别方法给出的结论是相同的?所以在一定程度上,我们可以认为前一个结论是后一个结论的推论。

让我们看个更加复杂一点的例子:

union {
  u_int16_t num;
  struct {
    u_int8_t a4 : 4;
    u_int8_t b8;
    u_int8_t c4 : 4;
  } b;
} a;
a.b.a4 = 0x01;
a.b.b8 = 0x0203;
a.b.c4 = 0x04;
a.num = ?

这个是不是复杂了很多,不要说实际中这样的应用不多,看看Linux内核中数据结构你就会明白,类似结构还是蛮多的。

当然又是和endian有关的问题,分类分析了:

big endian:

———————
| 7-4|3-0 | 7-4|3-0 |
———————
|  a[0]   |   a[1]  |
———————
| a4 |    b8   | c4 |
———————
| 01 | 02 | 03 | 04 |
———————
|     0x01020304    |
———————

所以,a.num = 0x01020304

little endian:

———————
| 7-4|3-0 | 7-4|3-0 |
———————
|  a[1]   |   a[0]  |
———————
| c4 |    b8   | a4 |
———————
| 04 | 02 | 03 | 01 |
———————
|     0x04020301    |
———————

所以,a.num = 0x04020301

就是这么简单,如果你真的懂了的话!

iphdr的那个结构就不用我来分析了吧?

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/33697.html

(0)

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信