我只想知道以下结构声明。哪一个更适合用于内存分配?为什么?那么在unsigned char和unsigned int的情况下填充呢?
struct data{
unsigned char a:3;
unsigned char b:4;
};
和
struct data{
unsigned int a:3;
unsigned int b:4;
};
答案 0 :(得分:7)
应使用signed int
,unsigned int
类型声明位字段。其他类型可能支持也可能不支持。
来自Atmel
in the C Standard, only “unsigned (int)” and “int” are acceptable datatypes for a bitfield member. Some compilers allow “unsigned char” .......
答案 1 :(得分:5)
关于c99标准(§6.7.2.1#4)
位字段应具有合格或不合格的类型 版本 _Bool ,签署int , unsigned int 或其他 实现定义的类型。
如果使用的实际类型说明符为int
或typedef-name
定义为int
,
然后是实现定义位字段是signed
还是unsigned
。
(§6.7.2.1#15)
结构或联合的末尾可能有未命名的填充。
实现可以分配足够大的任何可寻址存储单元来保存位域。
进一步(§6.7.2.1#11)
没有声明符的位字段声明,但只有冒号和a width,表示未命名的位字段。作为一个特例,一个 宽度为0的位字段结构成员表示不再进一步 比特字段将被打包到前一个单元中 bitfield,如果有的话,被放置了。
未命名的位字段结构成员对于填充以符合外部强制执行非常有用 布局。
答案 2 :(得分:2)
正如Amogh(坚定地)和PHIfounder所指出的那样,唯一完全可移植的类型是_Bool
,signed int
和unsigned int
。然而,许多编译器允许其他整数类型来填充位字段。实践中的位域通常用于表示器件寄存器,其中通常每个位或位组具有其自己的含义。比特的打包由C标准的 6.7.2.1 ad 11 决定
实现可以分配足够大的任何可寻址存储单元来保存位字段。如果剩余足够的空间,则紧跟在结构中的另一个位字段之后的位字段将被打包到相同单元的相邻位中。如果剩余的空间不足,则是否将不适合的位域放入下一个单元或重叠相邻单元是实现定义的。单元内的位域分配顺序(高阶到低阶或低阶到高阶)是实现定义的。可寻址存储单元的对齐未指定。
许多编译器采用了“可寻址存储单元”属于源中指定类型的约定。例如,gcc
编译器不允许类型为unsigned char
的9位位字段,但它确实允许unsigned int
类型。在您的示例中,使用gcc
的Pentium结构的unsigned char
编译器大小为1字节,而使用unsigned int
的结构将为4字节。许多编译器也采用了这样的惯例:如果位域不适合,它将不与下一个单元重叠。然而,这可以使用标准 6.7.2.1 ad 12 所指示的0宽度位字段来强制执行
没有声明符但只有冒号和宽度的位字段声明表示未命名的位字段。作为一种特殊情况,宽度为0的位域结构成员表示不会将其他位字段打包到放置前一位字段(如果有)的单元中。
如果将位字段与非位字段混合,则 6.7.2.1 ad 15 指示位字段和非位字段的可寻址单元将具有不同的地址< / p>
在结构对象中,非位字段成员和位字段所在的单元具有按声明顺序增加的地址。指向适当转换的结构对象的指针指向其初始成员(或者如果该成员是位字段,则指向它所在的单元),反之亦然。在结构对象中可能有未命名的填充,但不是在它的开头。
架构的一些体系结构应用程序二进制接口(ABI)强制执行实现定义的选择,以确保该体系结构的不同编译器的互操作性。
答案 3 :(得分:0)
哪一个更好用,unsigned char或unsigned int以及为什么?
unsigned int
以下内容不可移植,应予以考虑。
// Only portable bit field types are _Bool, signed int, unsigned int
// This is not portable.
struct data{
unsigned char a:3;
unsigned char b:4;
};
留下OP替代
struct data{
unsigned int a:3;
unsigned int b:4;
};
哪一个更适合用于内存分配?为什么?
如果 minimal memory 是主要目标,请不要使用位字段。在这种情况下,请使用最小整数类型:unsigned char
。添加函数或定义以获取和设置。
void data_a_set(unsigned char *data, unsigned a) {
*data = *data & ~7u | a & 7u;
}
unsigned data_a_get(unsigned char data) {
return data & 7u;
}
// or for a more generic approach
#define B_BITS_PRIOR 3 /* sum of all previous bit widths */
#define B_BITS 4
#define MASK(w,p) (((1u << (w)) - 1) << (p))
void data_b_set(unsigned char *data, unsigned b) {
*data &= ~MASK(B_BITS, B_BITS_PRIOR);
*data |= MASK(B_BITS, B_BITS_PRIOR) & (b << B_BITS_PRIOR);
}
unsigned data_b_get(unsigned char data) {
return (data & MASK(B_BITS, B_BITS_PRIOR) >> B_BITS_PRIOR;
}
对于比unsigned
更宽的类型,需要进行小的更改以确保更广泛的和以及转移操作。
unsigned char
可以包含在struct
中。
struct data {
unsigned char ab;
}