具有非连续布局的C位域元素

时间:2013-01-14 03:44:11

标签: c struct embedded unions bit-fields

我正在寻找最优雅的接口上的输入来放置内存映射的寄存器接口,其中目标对象在寄存器中被分割:

union __attribute__ ((__packed__)) epsr_t {
    uint32_t storage;
    struct {
        unsigned reserved0    : 10;
        unsigned ICI_IT_2to7  :  6; // TOP HALF
        unsigned reserved1    :  8;
        unsigned T            :  1;
        unsigned ICI_IT_0to1  :  2; // BOTTOM HALF
        unsigned reserved2    :  5;
    } bits;
};

在这种情况下,访问单个位T或任何reserved字段都可以正常工作,但要读取或写入ICI_IT需要的代码更像是:

union epsr_t epsr;
// Reading:
uint8_t ici_it = (epsr.bits.ICI_IT_2to7 << 2) | epsr.bits.ICI_IT_0to1;
// Writing:
epsr.bits.ICI_IT_2to7 = ici_it >> 2;
epsr.bits.ICI_IT_0to1 = ici_it & 0x3;

此时我已经失去了bitfield抽象试图提供的简单/便利的一大块。我考虑过宏观解决方案:

#define GET_ICI_IT(_e)      ((_e.bits.ICI_IT_2to7 << 2) | _e.bits.ICI_IT_0to1)
#define SET_ICI_IT(_e, _i)  do {\
    _e.bits.ICI_IT_2to7 = _i >> 2;\
    _e.bits.ICI_IT_0to1 = _i & 0x3;\
    while (0);
但是,作为一般规则,我并不是像这样的巨大粉丝,我讨厌在我读别人的代码时追逐它们,而对我来说,给别人带来这样的痛苦远非如此。我希望有一个创意技巧涉及结构/联合/你有什么能更优雅地隐藏这个对象的分裂性质(理想情况下是一个对象的简单成员)。

3 个答案:

答案 0 :(得分:8)

我不认为有一种'好'的方式,实际上我不会依赖于位域...有时最好只有一堆详尽的宏来做你想做的一切,文档他们很好,然后依靠他们封装了你的问题......

#define ICI_IT_HI_SHIFT   14
#define ICI_IT_HI_MASK    0xfc
#define ICI_IT_LO_SHIFT   5
#define ICI_IT_LO_MASK    0x02

// Bits containing the ICI_IT value split in the 32-bit EPSR
#define ICI_IT_PACKED_MASK  ((ICI_IT_HI_MASK << ICI_IT_HI_SHIFT) |     \
                             (ICI_IT_LO_MASK << ICI_IT_LO_SHIFT))

// Packs a single 8-bit ICI_IT value x into a 32-bit EPSR e
#define PACK_ICI_IT(e,x)  ((e & ~ICI_IT_PACKED_MASK) |                 \
                           ((x & ICI_IT_HI_MASK) << ICI_IT_HI_SHIFT) | \
                           ((x & ICI_IT_LO_MASK) << ICI_IT_LO_SHIFT)))

// Unpacks a split 8-bit ICI_IT value from a 32-bit EPSR e
#define UNPACK_ICI_IT(e)  (((e >> ICI_IT_HI_SHIFT) & ICI_IT_HI_MASK) | \
                           ((e >> ICI_IT_LO_SHIFT) & ICI_IT_LO_MASK)))

请注意,为了便于阅读,我没有将类型转换和普通宏内容放入其中。是的,我在提及可读性方面具有讽刺意味......

答案 1 :(得分:0)

如果您不喜欢使用内联函数的宏,但您使用的宏解决方案很好。

答案 2 :(得分:0)

您的编译器是否支持匿名联盟

我发现它是一个优雅的解决方案,摆脱了你的.bits部分。它不符合C99,但大多数编译器都支持它。它成为了C11的标准。

另请参阅此问题:Anonymous union within struct not in c99?