关于endian
来源:互联网 发布:胡为乎遑遑欲何之句式 编辑:程序博客网 时间:2024/05/29 13:23
关于endian
关于endian这个词Pconline上的解释如下:
“endian”这个词出自《格列佛游记》。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开,由此曾发生过六次叛乱,其中一个皇帝送了命,另一个丢了王位。
我们一般将endian翻译成“字节序”,将big endian和little endian称作“大尾”和“小尾”。初次遇到关于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的那个结构就不用我来分析了吧?
- 关于endian
- 关于Endian
- 关于little-endian 和 big-endian
- 关于Big Endian和Little Endian
- 关于 Big endian 和 Little endian
- [转] 关于Big-Endian 和Little-Endian
- 关于Big-Endian 和Little-Endian
- 关于Big Endian 和 Little Endian
- 关于Big-Endian 和Little-Endian
- 关于Big-Endian 和Little-Endian
- 关于Big-Endian 和Little-Endian
- 关于Big-Endian和Little-Endian
- 关于Big Endian 和 Little Endian
- 关于Big Endian 和 Little Endian
- 关于Big Endian 和 Little Endian
- 关于Big Endian 和 Little Endian
- 关于Big Endian 和 Little Endian
- 关于Big Endian 和 Little Endian
- oracle VARRAY数据类型
- Java Socket编程简捷学习过程
- C++中const用法总结
- 简单的J2EE(四)一些技术选型的建议
- RAD Studio XE2 官方 ISO 下载地址 (With Update1)
- 关于endian
- JAVA 文件上传与下载
- 如果后台的SVN服务器IP地址更改了,如何修改客户端的连接url呢?
- 学习嵌入式建议的书籍
- jdbc调用oracle procedure传递/返回批量数据
- Flex 展开树
- Python字符编码详解
- 如何自定义Struts2表单验证后的错误信息显示格式/样式
- 获得汉字拼音的首字母和全拼