c语言位域作用,C语言位域

在求职笔试中,C中的位域是一个常考点,特别是在嵌入式软件中更常见。位域的最大好处是可以根据自己需要定制位数,从而节省空间,例如:嵌入式编程稀缺的内存资源。还有在网络通讯中,对头信息部分的结构定义也常用到位域,少传一位是一位啊。

这里来分析EMC的一道笔试题(07年招聘试题):

1

typedef struct

bitstruct 2 { 3 int b1:5; 4 int :2; 5 int b2:2; 6 }bitstruct; 7 int main(int argc, char

*argv[]) 8 { 9 bitstruct b; 10

printf("%d\n",sizeof(bitstruct));

11

memcpy(&b,"EMC

Examination",sizeof(b));

12

printf("%d,%d\n",b.b1,b.b2); 13

return

0; 14

}

请问在little-endian systems(系统默认的存放顺序)中,输出结果是什么?

答案是

45,-2;

所需知识点:

1.位域的概念和特点

C语言允许在一个结构体中以位为单位来指定其成员所占内存长度,这种以位为单位的成员称为“位段”或称“位域”(bit

field)。(1)位段成员的类型必须指定为unsigned或int类型;(2)若某一位段要从另一个字开始存放,用:0长度为0的空位段,作用就是使下一个位段从下一个存储单位(视不同编译系统而异)开始存放;(3)一个位段必须存储在同一存储单元中,不能跨两个单元;(4)可以定义无名字段例如":2";(5)位段的长度不能大于存储单元的长度,也不能定义位段数组;(6)位段可以用整形格式符输出;(7)位段可以在数值表达式中引用,它会被系统自动地转换成整形数。[1][3]

2.Little-endiansystems的内存布局特点

先问一个问题:Endian这个词是什么意思?

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

我们一般将endian翻译成“字节序”,将big

endian和little

endian称作“大尾”和“小尾”。这也在当今的CPU派别中一样存在。Motorola的PowerPC系列CPU采用的Big-endian,

Intel的X86系列CPU采用的是Little-endian。Little-endian的特点是高高低低,即高位地址存放最高有效字节,低位地址存放最低有效字节;而Big-endian正好相反。下面用图的方式说明起来更直观,例如0x12345678(特别注意,这是单个数,不是字符串,如果是字符串就不一定这样了。之前没有特别注意这点,害的我多花了冤枉时间)。

Big Endian

低地址高地址----------------------------------------->

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| 12 | 34 | 56 | 78 |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Little

Endian

低地址高地址----------------------------------------->

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| 78 | 56 | 34 | 12 |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

上面的字节序的不同,在单机的操作中没有问题,因为一台单机就是采用单一的字节序嘛!但是在两个不同的主机进行协作时,就会出现问题了;另外在网络通讯中也同样会出现问题,详细参考[2]

就单个字节而言,也会有这样的问题:比特序有差别吗?

也分成两种序,如果我们处理的基本单位是字节以上的话,对此就不必担心了,因为CPU存储操作的最小单元是字节,所以比特位的顺序对我们来就是透明的,我们在读取某个字节时,不管它用的是Big

endian 还是Little

endian,我们读到的都是一个同样的字节,只不过硬件在读写时的顺序,一个是从高到底另一个是从低到高,对我们的使用不产生影响。但是如果涉及到位域的存放问题,还是要特别小心,上面这道题就是一个非常的好的例子。

Big Endian

msb lsb

---------------------------------------------->

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| 1 | 0 | 1 | 1 | 0 | 1 | 0 | 0 |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Little

Endian

lsb msb

---------------------------------------------->

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| 0 | 0 | 1 | 0 | 1 | 1 | 0 | 1 |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

3.memcpy()与strcpy()的区别

这个问题很简单,可以想象成这样:memcpy的基本单位是位,strcpy的基本单位是字符。所以,memcpy会根据提供的长度完全按位拷贝,而strcpy是两个字符串之间的拷贝。

回来原来的问题上,在采用little

endian的BUS64中,struct

bitstruct在没涉及到高低位问题时,也就是我们平时常会画出的一种形式是:

{b1 b1 b1 b1 b1 Ø Ø b2 b2 Ø Ø Ø

Ø Ø Ø Ø ØØØØØØØØ ØØØØØØØØ};

在内存中的实际布局是:

低地址高地址-------------------------------------------------------------->

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

|b2Ø Øb1

b1b1 b1

b1|Ø Ø Ø Ø Ø Ø

Ø b2|ØØØØØØØØ |ØØØØØØØØ|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Ø表示空填充,这当中包含一个原则:一个位域的存放不可以跨字存放,但可以跨字节存储;这里采用的比特续也是little

endian,说明了比特序对操作也是有影响的嘛!

memcpy按位拷贝“EMC Examination”到b中,一个字符是8位; 又因为sizeof(b)=4,所以只写入"EMC

"。"EMC "对应的位序列是:{0100 0101 0100

1101 0100 0011 0010

0000},从这里写到内存里的形式是:(在这里不要被little

endian给迷惑了,E不是放在高地址,参看上面红色的特别注意)

低地址高地址-------------------------------------------------------------->

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

|b2Ø

Øb1

b1b1 b1

b1|Ø

Ø Ø Ø Ø Ø Øb2|ØØØØØØØØ|ØØØØØØØØ||0 1 0 0 0 1 0 1|0 1 0 0 1 1

0 1|0100

0011|0010

0000|

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+printf("%d,%d\n",b.b1,b.b2);读出来的b1是00101,它的值是5;

b2是10,转换成十进制是-2。到了这一步,似乎题目已经解答出来了,但还有两个地方有疑惑:

1.struct bitstruct在内存中的位存放顺序是这样的么?

低地址高地址-------------------------------------------------------------->

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

|b2Ø

Øb1

b1b1 b1

b1|Ø

Ø Ø Ø Ø Ø Øb2|ØØØØØØØØ|ØØØØØØØØ|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

2.memcpy函数在按位拷贝时的拷贝顺序是这样的么?

低地址高地址-------------------------------------------------------------->

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|01000101|01001101|0100

0011|0010

0000|

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

关于上面两个问题的验证工作留给路过的朋友来做:-P ..... 欢迎批评指正

注解:转载自(忘了什么地方)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值