一个快速的问题:下面给出的结构中char c:4的含义是什么
struct s
{
char c:4;
}
提前致谢。
这是一个由 a 的四位部分组成的位字段char
。您可以定义更多位字段以将较大的类型细分为“nibblets”,如下所示:
struct s
{
char c:4;
char d:2;
char e:2;
};
这struct
定义了三个字段,全部“打包”到一个char
. 该c
字段可以保存 16 个不同的值;字段d
,e
每个字段可以保存四个值。
这char c:4
意味着它是一个char
大小变量,其中 4 位是变量c
。换句话说,c
不是指整个 8 位char
内存空间,只有 4 位。这是一种将标志和不常见的数据大小打包到结构中的机制。
位域是 C 语言的一个古怪特性,多年来其确切的规范和行为有些不一致。更高版本的 C 标准已经确定了行为的某些方面,足以阻止编译器做一些有用的事情,但不足以使它们以任何有用的方式可移植。
如果结构的两个或多个连续成员具有相同的底层整数类型,并且其字段名称后跟冒号和数字,则编译器将尝试将第一个之后的每个成员打包到与前一个相同的存储元素中。如果它不能这样做,它将前进到下一个存储元素。
因此,在unsigned short
16 位的机器上,声明:
struct {
unsigned short a1 : 5;
unsigned short a2 : 5;
unsigned short a3 : 7;
unsigned short a4 : 5;
unsigned short a5 : 4;
unsigned short a6 : 6;
}
编译器会将 a1 和 a2 打包成一个 16 位整数;由于 a3 不能与 a1 和 a2 放入相同的整数(总数为 17 位),因此它将开始一个新整数。尽管 a4 会与 a1 和 a2 一起位,但 a3 挡道的事实意味着它将与 a3 一起放置。然后 a5 将与 a3 和 a4 一起放置,填满第二个位置。A6 将获得一个 16 位的位置。
请注意,如果所有这些结构元素的基础类型都是 32-bit unsigned int
,则所有内容都可以打包到一个这样的项目中,而不是三个 16 位的项目。
坦率地说,我真的不喜欢位域的规则。它们的规则非常模糊,以至于一个编译器为位域数据生成的底层表示可能无法被另一个编译器读取,但它们足够具体,以至于禁止编译器生成可能有用的数据结构(例如,应该可以打包四个6 位数字转换为 3 字节(24 位)结构,但除非编译器碰巧有 24 位整数类型,否则有办法请求)。尽管如此,规则就是它们。