对于基于手臂的拱门来说,什么更好?
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;
};
对于基于手臂的拱门来说,什么更好?
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;
};
我认为处理器的架构对于这个问题并不重要。在许多方面,这纯粹是一个风格问题。
根据我的经验,大多数人倾向于使用无符号整数和按位运算:
#define MASK_B 0x20;
unsigned char field;
int b_is_set = field & MASK_B;
位域似乎从未真正在主流代码中流行起来。
话虽这么说,我会用你觉得更自然的那个。
首先要做的是考虑对齐,阅读更多关于unaligned -memory-access和mem_alignment的问题。
可扩展性或开销是第二个非常重要的事情。如果这个结构将被多次分配,例如缓存条目或将其与文件系统内部结构等结构一起使用,那么您需要保持紧凑。
可读性也很重要,但由于这是我们正在讨论的操作系统内核,您需要提供性能和维护,因此您应该有意识地做出权衡。
位域打包顺序是实现定义的。这意味着如果你声明
struct my_struct {
struct device *dev;
unsigned char a:1,
b:1,
c:1,
d:1;
};
完全由编译器决定在哪里a
或实际驻留在哪里。(不过,GCC 和其他一些编译器确实定义b
或c
取决于它们如何打包位域。)d
__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
第三位和d
第四位。
如果您的 C 编译器支持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
orb
是否已设置,请使用get(&t, MASK_A | MASK_B)
. 要检查是否同时设置了a
和b
,请使用(get(&t, MASK_A | MASK_B)) == (MASK_A | MASK_B))
。所有三个函数都返回生成的位掩码,并应用掩码,即所有其他位为零。
就个人而言,我更喜欢后一种方法,主要是因为我觉得它更明确(我完全可以控制),更通用(允许我不仅可以单独操作,还可以分组操作),并且更节省空间(因为编译器倾向于添加填充,除非您明确告诉他们不要通过例如命令行开关)。根据您使用标志的方式,我建议您通过宏或静态内联函数访问它们。
也就是说,如果结构是应用程序内部的,从不存储在大容量存储器中或传输,我不会对任何一种方法有任何真正的反对。