Big-Endian 和 Little-Endian 字节排序
字节排序 含义 Big-Endian 一个Word中的高位的Byte放在内存中这个Word区域的低地址处。 Little-Endian 一个Word中的低位的Byte放在内存中这个Word区域的低地址处。
必须注意的是:表中一个Word的长度是16位,一个Byte的长度是8位。如果一个数超过一个Word的长度,必须先按Word分成若干部分,然后每一部分(即每个Word内部)按Big-Endian或者Little-Endian的不同操作来处理字节。
一个例子: 如果我们将0x1234abcd写入到以0x0000开始的内存中,则结果为 big-endian little-endian 0x0000 0x12 0xcd 0x0001 0x34 0xab 0x0002 0xab 0x34 0x0003 0xcd 0x12 Top
5 楼shockwave_115(采姑娘的小蘑菇) 回复于 2005-06-18 14:06:48 得分 0 怎么写一个函数判断机器是big_endian还是little_endian?Top
6 楼zhousqy(标准C匪徒)(甩拉,甩拉) 回复于 2005-06-18 14:33:49 得分 7 #include <stdio.h>
int main(int argc, char **argv) { union { short s; char c[sizeof(short)]; } un;
un.s = 0x0102;
if (sizeof(short) == 2) { if (un.c[0] == 1 && un.c[1] == 2) printf("big-endian\n"); else if (un.c[0] == 2 && un.c[1] == 1) printf("little-endian\n"); else printf("unknown\n"); } else printf("sizeof(short) = %d\n", sizeof(short));
exit(0); } 测试下面说法:我们知道一个结构 在不同的compiler下其在内存中的map是不一样的。
比如在VC(little Endian) struct TypeA { unsigned long a:1; unsigned long b:1; unsigned long c:3; unsigned long d:3;
unsigned long e:1; unsigned long f:1; unsigned long g:1; unsigned long h:1; unsigned long i:1; unsigned long j:2; unsigned long k:1; unsigned long l:12; unsigned long m:1; unsigned long n:3; }
在Window下(little Endian)其在内存中的Map为: n|m|l|k|j|i|h|g|f|e|d|c|b|a
而在MIPS下(Big Endian)其在内存中的Map为: a|b|c|d|e|f|g|h|i|j|k|l|m|n;
这些都是编译器造成的影响;
奇怪的little/big endian问题,请大家发言 楼主mimepp(你好呀) 2005-06-21 12:36:42 在 VC/MFC / ATL/ActiveX/COM 提问 进来看帖子的朋友都帮着up一下,让帖子别沉了.
问题描述: 从网络上某window XP的PC上收到一串内容 buffer, 表示为16进制如下: (共11 bytes) 00 b9 0b ,01 00 00 00, 00 04 00 00 -----> 内存中看到的内容如上,从左往右是内存地址增加方向. 现在有个指针指向 "01" 的位置. 用char *data表示. 这个data的内容是要赋值给一个结构的. struct test { int a; int b; }; 即 void fun(char *data, int datalen) { struct test *t = (struct test*)data; //data指向"01"所在的地方. printf("result, a: 0x%08x, b: 0x%08x\n", t->a, t->b); printf("result, a: %d, b: %d\n", t->a, t->b); } 传进去的 datalen = 8;
得到的结果应该是 result, a: 0x00000001, b: 0x00000400 result, a: 1, b: 1024
也就是说,我要得到"01"后面, 每4个字节的内容到一个int中.
但实际运行的结果却不是如此. 实际的结果是: result, a: 0x010bb900, b: 0x00000000 result, a: 17545472, b: 0
即我本来想得到的数据应该为"01" 后面的内容,但实际的结果却是走到了"01"左边的几个字节上. b的内容也变成了"01" 后面的"00"的那4个字节.
以上的代码是运行在某ARM开发板上的结果. 开发板上sizeof(int)是 4 即4个字节表示一个整数. sizeof(struct test)为8 data的指针point为0x09...87, 后面的两位为87. 中间的没记下.
后来经过改写: struct test tmp; memcpy( &tmp, data, sizeof(sturct test)); printf("result, a: 0x%08x, b: 0x%08x\n", tmp->a, tmp->b); printf("result, a: %d, b: %d\n", tmp->a, tmp->b); 使用memcpy 来复制内存内容后,结果输出正确. memcpy应该是把data右边的内容copy正确到了tmp中.问题最后是解决了的.
疑问: 1. 有人说不是little/big endian的问题,是数据结构struct test对齐的问题. 大家什么意见? 说是从"data的指针point为0x09...87, 后面的两位为87." 看出的问题. 不被4整除? 好像不是这样吧.大家聊聊自己的看法. 2. 错误出现时, 取到的结果是 a: 01 0b b9 00 b: 00 00 00 00 也就是在字串被这样处理了 00 b9 0b 01, 00 00 00 00, 04 00 00 即data指向的"01"被当成了高位.低位在它的左边. 即得到的是"01"加上它左边的3个字符,而不是右边的3个字符. 不知是否这样解释? 但这个解释好像很奇怪喔. 怎么跑到了左边?
3. 一般大家讨论的情况可能只会涉及到 01 00 00 00, 00 04 00 00 这个的排列的内容的含义: 如: 一种排列为: 01 00 00 00 00 04 00 00 另一种排列为: 00 00 00 01 00 00 04 00
但我这里遇到的是实际运行系统中的现象. 和这个讨论有点不同. 请大家就我的实际例子来讨论. 4. 难道是内存中数据被其他的代码"踩到", 出错了? 5. 不知道代码中其他地方还有没有这样的后患.呵呵.
相关知识,来自网络: 1. Big-Endian 和 Little-Endian 翻译为: 大端,小端 2. Big-Endian 和 Little-Endian 这两个术语来自于 Jonathan Swift 的《《格利佛游记》其中交战的两个派别无法就应该从哪一端--小端还是大端--打开一个半熟的鸡蛋达成一致。:) 在那个时代,Swift是在讽刺英国和法国之间的持续冲突,Danny Cohen,一位网络协议的早期开创者,第一次使用这两个术语来指代字节顺序,后来这个术语被广泛接纳了 摘自《深入理解计算机系统》 3. 含义: big endian:最高字节在地址最低位,最低字节在地址最高位,依次排列。 little endian:最低字节在最低位,最高字节在最高位,反序排列。 没记错的话,除了moto的68K系列和dec的sparc是big endian外,常见的cpu都是little endian。ARM同时支持big和little,实际应用中通常使用little endian。
欢迎大家讨论. http://cache.baidu.com/c?word=struct%2Cendian&url=http%3A//topic%2Ecsdn%2Enet/t/20050621/12/4096371%2Ehtml&p=cb759a42dd9812a059ed8535540894&user=baidu
一个微软面试题--关于位结构体
2007-09-23 08:49:23 大中小 标签:学习公社 备案待查,指不定啥时候就用上了。 写出下列程序在X86上的运行结果。 struct mybitfields { unsigned short a : 4; unsigned short b : 5; unsigned short c : 7; }test;
void main(void) { int i; test.a=2; test.b=3; test.c=0; i=*((short *)&test); printf("%d ",i); } 这
个题的为难之处呢,就在于前面定义结构体里面用到的冒号,如果你能理解这个符号的含义,那么问题就很好解决了。这里的冒号相当于分配几位空间,也即在定义
结构体的时候,分配的成员a 4位的空间, b 5位,c 7位,一共是16位,正好两个字节。下面画一个简单的示意: 变量名 位数 test 15 14 13 12 11 10 9 |8 7 6 5 4 |3 2 1 0 test.a | |0 0 1 0 test.b |0 0 0 1 1 | test.c 0 0 0 0 0 0 0 | | 在
执行i=*((short *)&test);
时,取从地址&test开始两个字节(short占两个字节)的内容转化为short型数据,即为0x0032,再转为int型为
0x00000032,即50。输出的结果就是50。当然,这里还涉及到字节及位的存储顺序问题,后面再说。 前面定义的结构体被称为位结构体。所谓位结构体,是一种特殊的结构体,在需要按位访问字节或字的一个或多个位时,位结构体比按位操作要更方便一些。 位结构体的定义方式如下: struct [位结构体名]{ 数据类型 变量名:整数常数; ... }位结构变量; 说明: 1)这里的数据类型只能为int型(包括signed和unsigned); 2)整数常数必须为0~15之间的整数,当该常数为1时,数据类型为unsigned(显然嘛,只有一位,咋表示signed?光一符号?没意义呀); 3)按数据类型变量名:整数常数;方式定义的结构成员称为位结构成员,好像也叫位域,在一个位结构体中,可以同时包含位结构成员及普通的结构成员; 4)位结构成员不能是指针或数据,但结构变量可以是指针或数据; 5)位结构体所占用的位数由各个位结构成员的位数总各决定。如在前面定义的结构体中,一共占用4+5+7=16位,两个字节。另外我们看到,在定义位结构成员时,必须指定数据类型,这个数据类型在位结构体占用多少内存时也起到不少的作用。举个例子: struct mybitfieldA{ char a:4; char b:3; }testA; struct mybitfieldB{ short a:4; short b:3; }testB; 这
里,testA占用一个字节,而testB占用两个字节。知道原因了吧。在testA中,是以char来定义位域的,char是一个字节的,因此,位域占
用的单位也按字节做单位,也即,如果不满一个字节的话按一个字节算(未定义的位按零处理)。而在testB中,short为两个字节,所以了,不满两个字
节的都按两个字节算(未定义位按零处理) 关于位结构体在内存中的存储问题 Kevin‘s Theory #2: In a C
structure that contains bit fields, if field A is defined in front of
field B, then field A always occupies a lower bit address than field B.
(来自http://www./forum/showflat.php?Cat=&Board=linuxk&Number=638637&page=0&view=collapsed&sb=5&o=all&fpart=all) 说的是,在C结构体中,如果一个位域A在另一个位域B之前定义,那么位域A将存储在比B小的位地址中。 如果一个位域有多个位时,各个位的排列顺序通常是按CPU的端模式(Endianess)来进行的,即在大端模式(big endian)下,高有效位在低位地址,小端模式则相反。 补充说明一个关于位域与普通结构成员一起使用的问题 先看一个例子 struct mybitfield{ char a:4; char b:3; char aa; char c:1;}test; 这种情况下,test应该占几个字节呢?2个(4+3+1=8占一个字节,aa占一个)还是3个(4+3不足补一位,占一个字节,aa占一个字节,c占一个字节)? 写个小程序验证一下: int main(int argc, char* argv[]) { int i; test.a = 1; test.b = 1; test.aa = 1; test.c = 1;
i=*((short *)&test); printf("%d \n",i);
return 0; }
|