转  一个MS面试题_#单片机 300万段精彩视频抢先看 管理博客搜索帮助 A 鼠标双击滚屏 (1最快,10最慢) [VC] 一个微软面试题--关于位结构体作者:monkey 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 0test.a                       |           |0 0 1 0test.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.linuxforum.net/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;
}

输出结果是273,化为十六进制数0x111,可见是按三个字节来处理了(如果按两个字节处理的话,cba组成一个字节,是10010001(十六进制0x91)再加上aa,那就应该是0x191了)

举这个例子是为了说明一下,定义位域的话,最好是把所以有位域放在一起,这样可以节省空间(如果把c和aa换一下位置,那test就只占两个字节了)。另外也是为了强调一下位结构体的内存分配方式,按定义的先后顺序来分配,而位域(或成员)内的字节顺序则按照CPU的位顺序来进行(一般与CPU的端模式对应)。 本来想再整理一下关于冒号操作符的用法,写得够乱的了,就不再添乱了。改天重新整理吧。本文仅为提供更多信息,不代表新浪BLOG同意其观点或描述。如需转载请注明出处。 转  一个MS面试题_#单片机_02转  一个MS面试题_#单片机_03