2

对于基于手臂的拱门来说,什么更好?

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;
};
4

3 回答 3

4

我认为处理器的架构对于这个问题并不重要。在许多方面,这纯粹是一个风格问题。

根据我的经验,大多数人倾向于使用无符号整数和按位运算:

#define MASK_B 0x20;
unsigned char field;
int b_is_set = field & MASK_B;

位域似乎从未真正在主流代码中流行起来。

话虽这么说,我会用你觉得更自然的那个。

于 2012-12-03T19:53:14.997 回答
1

首先要做的是考虑对齐,阅读更多关于unaligned -memory-accessmem_alignment的问题。

可扩展性或开销是第二个非常重要的事情。如果这个结构将被多次分配,例如缓存条目或将其与文件系统内部结构等结构一起使用,那么您需要保持紧凑。

可读性也很重要,但由于这是我们正在讨论的操作系统内核,您需要提供性能和维护,因此您应该有意识地做出权衡。

于 2012-12-03T20:37:27.143 回答
1

位域打包顺序是实现定义的。这意味着如果你声明

struct my_struct {
    struct device  *dev;
    unsigned char   a:1,
                    b:1,
                    c:1,
                    d:1;
};

完全由编译器决定在哪里a或实际驻留在哪里。(不过,GCC 和其他一些编译器确实定义bc取决于它们如何打包位域。)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). 要测试aorb是否已设置,请使用get(&t, MASK_A | MASK_B). 要检查是否同时设置了ab,请使用(get(&t, MASK_A | MASK_B)) == (MASK_A | MASK_B))。所有三个函数都返回生成的位掩码,并应用掩码,即所有其他位为零。

就个人而言,我更喜欢后一种方法,主要是因为我觉得它更明确(我完全可以控制),更通用(允许我不仅可以单独操作,还可以分组操作),并且更节省空间(因为编译器倾向于添加填充,除非您明确告诉他们不要通过例如命令行开关)。根据您使用标志的方式,我建议您通过宏或静态内联函数访问它们。

也就是说,如果结构是应用程序内部的,从不存储在大容量存储器中或传输,我不会对任何一种方法有任何真正的反对。

于 2012-12-03T23:20:07.607 回答