C 对于位字段,使用无符号字符还是无符号整型更好?为什么?
我只想知道下面的结构声明。哪一个更好地用于内存分配?为什么?对于无符号char和无符号int,填充又如何呢C 对于位字段,使用无符号字符还是无符号整型更好?为什么?,c,linux,structure,bit-fields,C,Linux,Structure,Bit Fields,我只想知道下面的结构声明。哪一个更好地用于内存分配?为什么?对于无符号char和无符号int,填充又如何呢 struct data{ unsigned char a:3; unsigned char b:4; }; 及 位字段应使用类型有符号整数,无符号整数声明。其他类型可能受支持,也可能不受支持 从 在C标准中,只有“unsigned(int)”和“int”是位字段成员可接受的数据类型。有些编译器允许c99标准(§6.7.2.1#4)中的“无符号字符”… 位字段的类型应为合格或不合格
struct data{
unsigned char a:3;
unsigned char b:4;
};
及
位字段应使用类型
有符号整数
,无符号整数
声明。其他类型可能受支持,也可能不受支持
从
在C标准中,只有“unsigned(int)”和“int”是位字段成员可接受的数据类型。有些编译器允许c99标准(§6.7.2.1#4)中的“无符号字符”…
位字段的类型应为合格或不合格
\u Bool、有符号整数、无符号整数或其他版本
实现定义的类型
如果实际使用的类型说明符是int
或定义为int
的typedef名称
,
然后由实现定义位字段是有符号的
还是无符号的
(§6.7.2.1#15)
结构或联合的末尾可能有未命名的填充
一个实现可以分配任何足够大的可寻址存储单元来容纳一个位字段
进一步(§6.7.2.1#11)
一种位字段声明,没有声明符,只有冒号和
宽度,表示未命名的位字段。作为特例,a
宽度为0的位字段结构成员表示没有进一步的
位字段要打包到前一个字段所在的单元中
已放置位字段(如果有)
未命名的位字段结构成员可用于填充以符合外部施加的规则
布局。正如Amogh(坚定地)和PHIfounder指出的那样,唯一完全可移植的类型是\u Bool
、带符号int
和无符号int
。然而,许多编译器允许其他整数类型随意打包位字段。实际上,位字段通常用于表示设备寄存器,其中每个位或一组位通常有其自己的含义。位的包装由C标准的6.7.2.1 ad 11规定
一个实现可以分配任何足够大的可寻址存储单元来容纳一个位字段。如果仍有足够的空间,结构中紧跟在另一位字段之后的位字段应打包到同一单元的相邻位中。如果空间不足,则将定义是否将不适合的位字段放入下一个单元或与相邻单元重叠。单元内位字段的分配顺序(从高阶到低阶或从低阶到高阶)由实现定义。未指定可寻址存储单元的对齐方式
许多编译器采用了“可寻址存储单元”是源代码中指定类型的约定。例如,gcc
编译器不允许类型为unsigned char
的9位字段,但允许类型为unsigned int
的字段。在您的示例中,奔腾的gcc
编译器使用unsigned char
的结构大小为1字节,而使用unsigned int
的结构大小为4字节。许多编译器也采用了这样一种惯例,即如果一个位字段不合适,它将不会与下一个单元重叠。但是,可以使用标准的6.7.2.1 ad 12规定的0宽度位字段强制执行
没有声明符但只有冒号和宽度的位字段声明表示未命名的位字段。作为一种特殊情况,宽度为0的位字段结构成员表示不再将更多的位字段打包到前一位字段(如果有)所在的单元中
如果将位字段与非位字段混合,则6.7.2.1 ad 15规定位字段和非位字段的可寻址单元将具有不同的地址
在结构对象中,非位字段成员和位字段所在的单元的地址按声明顺序递增。经过适当转换的结构对象指针指向其初始成员(如果该成员是位字段,则指向其所在的单元),反之亦然。结构对象中可能有未命名的填充,但在其开头可能没有
体系结构的某些体系结构应用程序二进制接口(ABI)强制执行实现定义的选择,以确保该体系结构的不同编译器的互操作性
使用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;
};
这就留下了另一种选择
struct data{
unsigned int a:3;
unsigned int b:4;
};
哪一个更好地用于内存分配?为什么 如果最小内存是主要目标,则不要使用位字段。在本例中使用最小整数类型:
无符号字符
。添加要获取和设置的函数或定义
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;
}
为什么更好?时间、空间、温度、情绪……?也请看@BryanOlivier,以便更好地记忆allocation@Chinna,内存分配与此无关,因为您指定的是字段占用的位数。C指定
\u Bool、signed int、unsigned int
是可接受的,而不仅仅是这个答案的2。艾特梅尔城已经过时了。
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;
}
struct data {
unsigned char ab;
}