我试图找到一个不写的原因
struct bitfield {
signed foo:4;
unsigned bar:2;
};
而不是详细说明
struct bitfield {
signed int foo:4;
unsigned int bar:2;
};
由于在冒号后明确指定了位域的每个成员的大小,是否有任何缺点?
如果我使用char
,short
,long
,long long
,这是否重要?指定的位域位数必须总是小于声明类型的宽度吗?
找到一些相关问题:
答案范围从
int
或_Bool
和_Bool
,signed int
,unsigned int
或其他一些实现定义的类型。 (C99 6.2.7.1(4))在这种情况下:这个非特定的某些其他实现定义的类型可能是什么样的,以及我在这个地方的选择可能会产生哪些其他缺点?
答案 0 :(得分:3)
C99要求宽度表达式“不超过指定类型的对象中的位数”,因此如果使用的类型太小,代码将无法编译或在至少不是便携式的。见§6.7.2.1(3)。
关于更新的第三个问题和一般情况,“究竟是什么后果?”问题,可能受影响的事情是:可移植性,对齐和填充。该标准仅为第一个提供了明确的规范。在没有位域的情况下,通常可能基于预测编译器将如何生成最佳对齐值来排列对齐和填充。虽然不能保证,但在某些使用 short 之类的环境中,由于减少了对齐和填充,因此可以节省内存。
实现精确布局和可移植性偶尔冲突的目标的一种可能方法是声明内存中没有位字段的数据结构,可能使用<stdint.h>
类型。然后,如果要使用位字段来解码某些内容,请将内存中的源对象分配给临时变量,该临时变量是位字段和位特定类型的并集,或者通过强制转换来故意违反类型惩罚规则指针。 (Linux一直到处都这样做。)
更好的方法可能是避免位字段。
答案 1 :(得分:2)
在两个版本的代码中,宽度都是明确的;它是有符号和无符号int
的宽度。 signed
只是int
的别名,signed int
也是。unsigned
。同样,unsigned int
是signed
的别名。孤独的unsigned
和{{1}}不是修饰符,而是类型名称。