Как я могу получить битовые поля, чтобы расположить мои биты в правильном порядке? - PullRequest
4 голосов
/ 19 апреля 2010

Начнем с того, что рассматриваемое приложение всегда будет работать на одном и том же процессоре, а компилятор всегда gcc, поэтому меня не волнует, что битовые поля не переносимы.

gcc размещает битовые поля так, чтобы первое перечисленное поле соответствовало младшему значащему биту байта. Таким образом, следующая структура с a = 0, b = 1, c = 1, d = 1, вы получите байт значения е0.

struct Bits {
  unsigned int a:5;
  unsigned int b:1;
  unsigned int c:1;
  unsigned int d:1;
} __attribute__((__packed__));

(На самом деле, это C ++, поэтому я говорю о g ++.)

Теперь, допустим, я хотел бы, чтобы a было шестизначным целым числом.

Теперь я понимаю, почему это не сработает, но я кодировал следующую структуру:

struct Bits2 {
  unsigned int a:6;
  unsigned int b:1;
  unsigned int c:1;
  unsigned int d:1;
} __attribute__((__packed__));

Установка b , c и d в 1 и a в 0 приводит к следующим двум байтам:

c0 01

Это не то, что я хотел. Я надеялся увидеть это:

e0 00

Есть ли способ указать структуру, которая имеет три бита в старших битах первого байта и шесть битов, охватывающих пять младших бит первого байта и старший бит второго?

Пожалуйста, имейте в виду, что я не могу контролировать, где эти биты должны быть размещены: это макет битов, которые определяются чьим-либо интерфейсом.

Ответы [ 3 ]

3 голосов
/ 19 апреля 2010

(Обратите внимание, что все это - специфичные для gcc комментарии - я хорошо знаю, что расположение битовых полей определяется реализацией).

Не на машине с прямым порядком байтов: проблема в том, что на машине с прямым порядком байтов старший значащий бит второго байта не считается «смежным» с младшими значащими битами первого байта.

Однако вы можете комбинировать битовые поля с функцией ntohs():

union u_Bits2{
    struct Bits2 {
      uint16_t _padding:7;
      uint16_t a:6;
      uint16_t b:1;
      uint16_t c:1;
      uint16_t d:1;
    } bits __attribute__((__packed__));
    uint16_t word;
}

union u_Bits2 flags;
flags.word = ntohs(flag_bytes_from_network);

Однако я настоятельно рекомендую вам избегать битовых полей и вместо этого использовать сдвиг и маски.

3 голосов
/ 19 апреля 2010

Обычно вы не можете делать строгие предположения о том, как объединение будет упаковано, каждая реализация компилятора может по-разному упаковать его (для экономии места или выравнивания битовых полей внутри байтов).

Я бы предложил вам поработать с маскирующими и побитовыми операторами ..

из эта ссылка :

Основное использование битовых полей - либо для плотной упаковки данных, либо для возможности указания полей в некоторых внешне созданных файлах данных. C не дает гарантии упорядочения полей внутри машинных слов, поэтому, если вы используете их по последней причине, ваша программа будет не только непереносимой, но и зависимой от компилятора. Стандарт гласит, что поля упакованы в «единицы хранения», которые обычно являются машинными словами. Порядок упаковки и то, может ли битовое поле пересекать границу блока хранения, определяются реализацией. Для принудительного выравнивания по границе единицы хранения используется поле нулевой ширины перед тем, которое вы хотите выровнять.

0 голосов
/ 19 апреля 2010

C / C ++ не имеет средств для определения структуры структуры побитовой памяти, поэтому вам потребуется вручную сдвигать биты и маскировать их на 8 или 16-битных (без знака) целых числах (uint8_t, uint16_t из <stdint.h> или <cstdint>).

Из дюжины известных мне языков программирования только очень немногие позволяют вам указывать побитовую разметку памяти для битовых полей: Ada, Erlang, VHDL (и Verilog).

(Сообщество вики, если вы хотите добавить больше языков в этот список.)

...