分享

位域排序structendian

 ShaneWu 2008-09-27

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;
}

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多