基于手臂的弓有什么好处?
struct my_struct{
struct device *dev;
unsigned char a:1,
b:1,
v:1,
d:1;
};
或者定义一个char并使用位操作:
struct my_struct{
struct device *dev;
unsigned char abcd;
};
答案 0 :(得分:4)
我不认为处理器的架构对这个问题很重要。在许多方面,这纯粹是一种风格问题。
根据我的经验,大多数人倾向于使用无符号整数和逐位运算:
#define MASK_B 0x20;
unsigned char field;
int b_is_set = field & MASK_B;
在主流代码中,位域似乎从未真正起飞。
话虽如此,我会用你觉得更自然的一切。
答案 1 :(得分:1)
要做的第一件事就是考虑对齐,详细了解这些问题unaligned-memory-access和mem_alignment。
可伸缩性或开销是第二个非常重要的事情。如果这个结构将被多次分配,例如缓存条目或者使用文件系统内部结构,那么你需要保持紧凑。
可读性也非常重要,但由于这是一个操作系统内核,我们所说的是你需要提供的性能和维护,这是你应该有意识地做出的权衡。
答案 2 :(得分:1)
位字段打包顺序是实现定义的。这意味着如果你宣布
struct my_struct {
struct device *dev;
unsigned char a:1,
b:1,
c:1,
d:1;
};
完全取决于编译器决定a
或b
或c
或d
实际驻留在哪里。(GCC和其他一些编译器确定{{ 1}}或__BIG_ENDIAN_BITFIELD
取决于它们如何打包位域。)
另一方面,如果你定义
__LITTLE_ENDIAN_BITFIELD
您知道struct my_struct {
struct device *dev;
unsigned char abcd;
};
#define MASK_A (1U << 0U)
#define MASK_B (1U << 1U)
#define MASK_C (1U << 2U)
#define MASK_D (1U << 3U)
static inline unsigned char get(const struct my_struct *const m, const unsigned char mask)
{
return m->abcd & mask;
}
static inline unsigned char set(struct my_struct *const m, const unsigned char mask, const unsigned char value)
{
m->abcd = (m->abcd & mask) | (mask & value);
return m->abcd & mask;
}
static inline unsigned char flip(struct my_struct *const m, const unsigned char mask)
{
m->abcd ^= mask;
return m->abcd & mask;
}
映射到指针后面字节中的最低有效位,a
映射到第二位,b
第三位,c
第四位。< / p>
如果你的C编译器支持d
,那么这些函数和宏一样快,但没有问题宏有wrt。副作用。
这也允许您将位字段作为一个组进行操作。例如,要在结构static inline
中设置b
,您需要使用t
。要设置set(&t, MASK_B, MASK_B)
但要清除b
,您需要使用a
。要测试是否设置了set(&t, MASK_A | MASK_B, MASK_B)
,请使用a
。要测试是否设置了get(&t, MASK_A)
或a
,请使用b
。要检查是否设置了get(&t, MASK_A | MASK_B)
和a
,请使用b
。所有三个函数都返回结果位掩码,应用掩码,即所有其他位为零。
就个人而言,我更喜欢后一种方法,主要是因为我觉得它更明确(我完全掌控),更多功能(允许我不仅可以单独操作它们,而且可以分组操作),并且更节省空间(因为编译器倾向于添加填充,除非你明确告诉他们不要通过例如命令行开关)。根据您使用标志的方式,我建议您通过宏或静态内联函数访问它们。
那就是说,如果结构是应用程序的内部结构,从不存储在大容量存储器中或传输,我不会对这两种方法都有任何实际的反对意见。