【问题标题】:Is it possible to use array of bit fields?是否可以使用位域数组?
【发布时间】:2017-06-14 13:53:36
【问题描述】:

我很想知道,是否可以使用位域数组?喜欢:

struct st
{
  unsigned int i[5]: 4;
}; 

【问题讨论】:

  • 请注意,大多数最近的 C 代码不再使用位域。一个有用的替代方法是使用位掩码字段,并对它们进行按位运算。顺便说一句,编译器会生成等效代码。
  • @BasileStarynkevitch:我想知道你是从哪里得出的。使用位域比使用位运算处理位掩码域更不容易出错。

标签: c++ c arrays struct bit-fields


【解决方案1】:

不,你不能。位域只能与整型变量一起使用。

C11-§6.7.2.1/5

位字段的类型应为_Boolsigned intunsigned int 或其他一些实现定义的类型的限定或非限定版本。

您也可以这样做

struct st
{
    unsigned int i: 4;  
} arr_st[5]; 

但它的大小将是 struct 的大小的 5 倍(如 @comment 中提到的 @Jonathan Leffler)有 5 个成员,每个成员都有位字段 4。所以,这里没有多大意义。

你可以更仔细地做到这一点

struct st
{
    uint8_t i: 4;   // Will take only a byte
} arr_st[5]; 

【讨论】:

  • 但它的大小 (struct st { unsigned int i: 4; } arr_st[5]; 很可能是 unsigned int 大小的 5 倍;它不会是 20 位长。
  • @JonathanLeffler;是的。但没有其他方法可以声明位域数组。
  • @hacks 感谢您的帮助。
  • type uint8_t 可能不可用。 struct st { unsigned char i: 4; } arr_st[5]; 或只是 unsigned char arr[5]; 似乎更可取。
  • @IlmariKaronen;我的意思是说 struct arr_st 将是 5struct stt { unsigned int i: 4; unsigned int j: 4; unsigned int k: 4; unsigned int l: 4; unsigned int m: 4; } s; 这样的 struct 的倍数
【解决方案2】:

C 不支持位域数组,所以简短的回答是否定的。

对于非常大的数组,可能值得以这种方式打包值,每字节 2 个:

#define ARRAY_SIZE  1000000

unsigned char arr[(ARRAY_SIZE + 1) / 2];

int get_4bits(const unsigned char *arr, size_t index) {
    return arr[index >> 1] >> ((index & 1) << 2);
}

int set_4bits(unsigned char *arr, size_t index, int value) {
    arr[index >> 1] &= ~ 0x0F << ((index & 1) << 2);
    arr[index >> 1] |= (value & 0x0F) << ((index & 1) << 2);
}

【讨论】:

    【解决方案3】:

    您可以为这种情况编写自己的类。例如:

    template <typename T, size_t ITEM_BIT_SIZE>
    class BitArrayView {
    private:
        static const size_t ARRAY_ENTRY_BITS = sizeof(T) * 8;
        static const T ITEM_MASK = (~((T) 0)) >> (ARRAY_ENTRY_BITS - ITEM_BIT_SIZE);
        T* arr;
    public:
        struct ItemMutator {
            BitArrayView* owner;
            size_t index;
            T operator=(T value) {
                return owner->set(index, value);
            }
            operator T() {
                return owner->get(index);
            }
        };
        const size_t bitSize;
        BitArrayView(T* arr, size_t length) : arr(arr), bitSize((length * ARRAY_ENTRY_BITS) / ITEM_BIT_SIZE) {}
        T get(size_t index) const {
            size_t bitPos = index * ITEM_BIT_SIZE;
            size_t arrIndex = bitPos / ARRAY_ENTRY_BITS;
            size_t shiftCount = bitPos % ARRAY_ENTRY_BITS;
            return (arr[arrIndex] >> shiftCount) & ITEM_MASK;
        }
        T set(size_t index, T value) {
            size_t bitPos = index * ITEM_BIT_SIZE;
            size_t arrIndex = bitPos / ARRAY_ENTRY_BITS;
            size_t shiftCount = bitPos % ARRAY_ENTRY_BITS;
            value &= ITEM_MASK; // trim
            arr[arrIndex] &= ~(ITEM_MASK << shiftCount); // clear target bits
            arr[arrIndex] |= value << shiftCount; // insert new bits 
            return value;
        }
        ItemMutator operator[](size_t index) {
            return { this, index };
        }
    };
    

    然后你可以像访问“位域”数组一样访问它:

    // create array of some uints
    unsigned int arr[5] = { 0, 0, 0, 0, 0 };
    
    // set BitArrayView of 3-bit entries on some part of the array 
    // (two indexes starting at 1)
    BitArrayView<unsigned int, 3> arrView(arr + 1, 2);
    
    // should equal 21 now => (2 * 32) / 3
    arrView.bitSize == 21;
    
    for (unsigned int i = 0; i < arrView.bitSize; i++) {
        arrView[i] = 7; // eg.: 0b111;
    }
    
    // now arr[1] should have all bits set
    // and arr[2] should have all bits set but last one unset => (2 * 32) % 3 = 1
    // the remaining arr items should stay untouched
    

    这是一个简单的实现,应该只适用于无符号的后备数组。

    注意operator[] 中的“突变器技巧”;)。

    当然也可以实现其他一些运算符。

    【讨论】:

      猜你喜欢
      • 2020-12-15
      • 1970-01-01
      • 1970-01-01
      • 2012-11-03
      • 2021-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-19
      相关资源
      最近更新 更多