Будет ли это битовое поле работать так, как я ожидаю? - PullRequest
4 голосов
/ 13 октября 2011

Я немного читал о битовых полях в C, о том, как стандарт C не устанавливает какой-либо конкретный порядок полей в машинном слове и т. Д.

Надеюсь, этот вопрос соответствует формату SO.

Мой вопрос заключается в том, будет ли моя структура (определение следующее) действительно работать так, как я ожидаю. Вот определение, которое я придумал, а затем я буду обсуждать, что я хочу:

typedef enum {
   STATE_ONE,
   STATE_TWO,
   STATE_THREE,
   STATE_FOUR
} __attribute__ ((packed)) State;

typedef struct MyStruct {
   // One of State enum (maximum of 4 states).
   unsigned state : 2;

   // Remaining 30 bits are used differently depending on 'state'.
   union {
      // If 'state' is STATE_ONE (0), the remaining bits are an ID number.
      unsigned id : 30;

      /* 
       * For all other states, the remaining bits are the 2-tuple:
       *  (buffer A index, buffer B index).
       */
      struct {
         unsigned bufferAIdx : 16;
         unsigned bufferBIdx : 14;
      } __attribute__ ((packed)) index;
   } __attribute__ ((packed));
} __attribute__ ((packed)) MyStruct;

(Это для gcc, таким образом, директивы __attribute__).

Вы, вероятно, можете сказать, для чего я: в зависимости от значения поля 'state', я хочу использовать оставшиеся 30 бит для разных целей. Это должен быть либо идентификационный номер, либо два набора индексов в различных буферах. И каждый экземпляр MyStruct должен занимать максимум 5 байтов.

Так что я хочу иметь возможность сделать что-то на этот счет:

MyStruct a, b;
a.state = STATE_ONE;
a.id = 123456;

b.state = STATE_THREE;
b.index.bufferAIdx = 6;
b.index.bufferBIdx = 2;

В основном я ищу информацию о том, "правильно ли это делать". Другими словами, я неправильно использую идеи битовых полей / союзов здесь? Если вы собираетесь поддерживать этот код, будете ли вы в ужасе, увидев это? Или вы бы предпочли, чтобы весь объект данных хранился в типе uint32_t и управлялся с помощью маскирования и сдвига?

1 Ответ

4 голосов
/ 13 октября 2011

Поскольку начало любого union или struct будет выровнено по границе, вы не сможете таким образом уместить все ваши данные в 32 бита.Вы должны инкапсулировать свои union и struct в обратном порядке, как показано ниже (атрибуты удалены для удобства чтения):

typedef struct MyStruct {
   union {
      struct {
         unsigned state :  2;
         unsigned id    : 30;
      }
      struct {
         unsigned /* unused */ :  2; 
         unsigned bufferAIdx   : 16;
         unsigned bufferBIdx   : 14;
      };
   };
};
...