c语言程序个位,C语言位字段

2022-08-04 14:40:59 浏览数 (1)

位字段(bit-field)是一个由具有特定数量的位组成的整数变量。结构或联合的成员也可以是位字段。如果连续声明多个小的位字段,编译器会将它们合并成一个机器字(word)。这使得小单元信息具有更加紧凑的存储方式。当然,也可以使用位运算符来独立处理特定位,但是位字段允许我们利用名称来处理位,类似于结构或联合的成员。

位字段的声明格式为:

类型[成员名称]:宽度;

各部分的详细描述如下:

(1) 类型

指定一个整数类型,用来决定该位字段值被解释的方式。类型可以是 _Bool、int、signed int、unsigned int,或者为所选实现版本所提供的类型。这里的类型也可以包含类型限定符。

具有 signed int 类型的位字段会被解释成有符号数;具有 unsigned int 类型的位字段会被解释成无符号数。具有 int 类型的位字段可以是有符号或无符号的类型,由编译器决定。

(2) 成员名称

成员名称是可选的(可以不写)。但是,如果声明了一个无名称的位字段,就没有办法获取它。没有名称的位字段只能用于填充(padding),以帮助后续的位字段在机器字中对齐到特定的地址边界。

(3) 宽度

位字段中位的数量。宽度必须是一个常量整数表达式,其值是非负的,并且必须小于或等于指定类型的位宽。无名称位字段的宽度可以是 0。在这种情况下,下一个声明的位字段就会从新的可寻址内存单元开始。

当在一个结构或联合内声明一个位字段的时候,编译器会分配一个足以容纳它的可寻址内存单元。通常情况下,被分配的内存单元是一个 int 类型的机器字。

如果紧接着的位字段适合同一内存单元中剩下的空间,那么就被定义到与前面的位字段紧邻的位置。如果不适合的话,那么编译器就分配另外的内存单元,并在新单元的起始放置下一个位字段,或者跨过前一个内存单元的结尾和下一个内存单元的开头。

下面的例子重新定义了结构类型 struct Date,让其成员 month 和 day 只占据各自需要的位数。为了展示 _Bool 类型的位字段,我们为夏令时设定一个标签。这段代码以目标机器使用至少 32 位字为前提:

代码语言:javascript复制
struct Date {

unsigned int month : 4; // 1是1月;12是12月

unsigned int day : 5; // 月份中的日(1~31)

signed int year : 22; // (-2097152~ 2097151)

_Bool isDST : 1; // 如果是夏令时,则为true

};

n 位的位字段可以有 2n 个不同的值。结构成员 month 的取值范围是 0~15;成员 day 的取值范围是 0~31;成员 year 的值范围是 -2097152~ 2097151。我们可以使用常见的初始化列表方式初始化一个 struct Date 类型的对象:

struct Date birthday = { 5, 17, 1982 };

对象 birthday 占据的存储空间大小与一个 32 位的 int 整数对象一样。和结构中其他成员所不同的是,位字段通常不会占据可寻址的内存位置,因此无法对位字段采用地址运算符(&)或宏 offsetof。

但是在其他方面,可以将位字段看作结构或联合成员,使用点和箭头运算符来获取,并以类似对待 int 或 unsigned int 变量的方式对其进行算术运算。因此,使用位字段重新定义的 Date 结构在函数 dateAsString()中不需作任何修改:

代码语言:javascript复制
const char *dateAsString( struct Date d )

{

static char strDate[12];

sprintf( strDate, "d/d/d", d.month, d.day, d.year );

return strDate;

}

下面的语句为对象 birthday 调用函数 dateAsString(),并采用标准函数 puts()输出结果:

puts( dateAsString( birthday ));

0 人点赞