请选择 进入手机版 | 继续访问电脑版
网络

教育改变生活

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 22|回复: 0

【C语言】位域(位段)

[复制链接]

645

主题

652

帖子

2934

积分

版主

Rank: 7Rank: 7Rank: 7

积分
2934
发表于 3 天前 | 显示全部楼层 |阅读模式
在结构体定义时,我们可以指定某个成员变量所占用的二进制位数(Bit),这就是位域。请看下面的例子:
  • struct bs{
  •     unsigned m;
  •     unsigned n: 4;
  •     unsigned char ch: 6;
  • };


:后面的数字用来限定成员变量占用的位数。成员 m 没有限制,根据数据类型即可推算出它占用 4 个字节(Byte)的内存。成员 n、ch 被:后面的数字限制,不能再根据数据类型计算长度,它们分别占用 4、6 位(Bit)的内存。

n、ch 的取值范围非常有限,数据稍微大些就会发生溢出,请看下面的例子:
  • #include <stdio.h>
  • int main(){
  •     struct bs{
  •         unsigned m;
  •         unsigned n: 4;
  •         unsigned char ch: 6;
  •     } a = { 0xad, 0xE, '$'};
  •     //第一次输出
  •     printf("%#x, %#x, %c\n", a.m, a.n, a.ch);
  •     //更改值后再次输出
  •     a.m = 0xb8901c;
  •     a.n = 0x2d;
  •     a.ch = 'z';
  •     printf("%#x, %#x, %c\n", a.m, a.n, a.ch);
  •     return 0;
  • }


运行结果:
0xad, 0xe, $
0xb8901c, 0xd, :

对于 n 和 ch,第一次输出的数据是完整的,第二次输出的数据是残缺的。

第一次输出时,n、ch 的值分别是 0xE、0x24('$' 对应的 ASCII 码为 0x24),换算成二进制是 1110、10 0100,都没有超出限定的位数,能够正常输出。

第二次输出时,n、ch 的值变为 0x2d、0x7a('z' 对应的 ASCII 码为 0x7a),换算成二进制分别是 10 1101、111 1010,都超出了限定的位数。超出部分被直接截去,剩下 1101、11 1010,换算成十六进制为 0xd、0x3a(0x3a 对应的字符是 :)。

C语言标准规定,位域的宽度不能超过它所依附的数据类型的长度。通俗地讲,成员变量都是有类型的,这个类型限制了成员变量的最大长度,:后面的数字不能超过这个长度。

例如上面的 bs,n 的类型是 unsigned int,长度为 4 个字节,共计 32 位,那么 n 后面的数字就不能超过 32;ch 的类型是 unsigned char,长度为 1 个字节,共计 8 位,那么 ch 后面的数字就不能超过 8。

我们可以这样认为,位域技术就是在成员变量所占用的内存中选出一部分位宽来存储数据。

C语言标准还规定,只有有限的几种数据类型可以用于位域。在 ANSI C 中,这几种数据类型是 int、signed int 和 unsigned int(int 默认就是 signed int);到了 C99,_Bool 也被支持了。
但编译器在具体实现时都进行了扩展,额外支持了 char、signed char、unsigned char 以及 enum 类型,所以上面的代码虽然不符合C语言标准,但它依然能够被编译器支持。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

WEB前端

QQ|手机版|小黑屋|金桨网|助学堂  咨询请联系站长。

GMT+8, 2024-7-13 12:07 , Processed in 0.034597 second(s), 22 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表