IAR, битовые поля (bitfields) Печать
Добавил(а) microsin   

В стандарте ISO/ANSI C типы int, signed int, и unsigned int могут использоваться как базовый тип для целых битовых полей (integer bitfields).

Реализация битовых полей, заданных через int та же самая, как и для signed int или unsigned int. В компиляторе IAR C/C++ для ARM, битовые поля, заданные через int, интерпретируются как заданные через unsigned int. Кроме того, любой тип целого числа может быть использован в качестве основного типа, когда разрешены расширения языка. Битовые поля в выражениях будут иметь тот же тип данных, что и базовый целый тип.

Компилятор размещает битовые поля в носителе, базируясь на используемом порядке байт (имеется в виду режим little-endian или big-endian). Если по умолчанию работает порядок байт little-endian, и компилятор размещает поля бит от младшего значащего бита (least significant) до старшего (most significant) в байтах переменной контейнера. Если по умолчанию режим big-endian, то компилятор раскладывает битовые поля в контейнере от старших бит до младших. Битовое поле помещается назначенное на последнее доступное место в контейнере, так чтобы все поле уместилось в этот контейнер целиком. Это означает, что контейнер битового поля может накладываться на другие поля структуры, пока порядок полей в структуре сохраняется. Например, в режиме big-endian имеется структура:

struct example{
   char a;
   short b : 10;
   int c : 6;};

Здесь первая декларация создаст unsigned char, который разместится в битах от 24
до 31. Вторая декларация создаст поле signed short integer размером 10 бит. Это поле займет биты от 15 до 6 включительно, поскольку он не поместится в оставшиеся 8 бит первого контейнера short integer. Последнее поле будет размещено в биты от 0 до 5. Получится 32-битное значение, и структура будет размещена в памяти следующим образом:

IAR-bitfields-example-big-endian-mode

Размещение битовых полей структуры в памяти, режим big-endian.

Используйте директиву #pragma bitfields=disjoint_types, чтобы принудительно разъединить контейнеры битовых полей, или другими словами, сделать так, чтобы контейнеры не перекрывались. В этом случае структура вышеуказанного примера будет выглядеть так:

IAR-bitfields-example-big-endian-mode-forced-disjoint

Размещение битовых полей структуры в памяти, режим big-endian, применена директива disjoint_types.

Используйте директиву #pragma bitfields=reversed_disjoint_types для размещения битовых полей от наименее значащего бита (least significant bit) к наиболее значащему (most significant bit) в не перекрывающихся контейнерах.

[Сравнение битовых полей и битовых масок]

Раньше я очень увлекался использованием масок для управления отдельными битовыми флажками, считая это довольно эффективным методом обработки двоичных значений. Упрощенный пример (подключение заголовков определения типов bool, u8, u8 для простоты не показано):

typedef struct _TExampleBitfields
{
   u16 val16bit;
   u8 bits;
}TExampleBitfields;
 
#define BIT0MASK (1 << 0)
#define BIT1MASK (1 << 1)
#define BIT2MASK (1 << 2)
#define BIT3MASK (1 << 3)
#define BIT4MASK (1 << 4)
#define BIT5MASK (1 << 5)

TExampleBitfields example;void main (void)
{
   u8 cnt;
   while (1)
   {
      example.bits = cnt & (1 << 0)? example.bits | BIT0MASK: example.bits & ~BIT0MASK;
      example.bits = cnt & (1 << 1)? example.bits | BIT1MASK: example.bits & ~BIT1MASK;
      example.bits = cnt & (1 << 2)? example.bits | BIT2MASK: example.bits & ~BIT2MASK;
      example.bits = cnt & (1 << 3)? example.bits | BIT3MASK: example.bits & ~BIT3MASK;
      example.bits = cnt & (1 << 4)? example.bits | BIT4MASK: example.bits & ~BIT4MASK;
      if (example.bits & BIT4MASK)
         example.bits = cnt & (1 << 4)? example.bits | BIT5MASK: example.bits & ~BIT5MASK;
      cnt++;
   }
}

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

typedef struct _TExampleBitfields
{
   u16 val16bit;
   bool bit0: 1;
   bool bit1: 1;
   bool bit2: 1;
   bool bit3: 1;
   bool bit4: 1;
   bool bit5: 1;
}TExampleBitfields;
TExampleBitfields example;

void main (void) { u8 cnt; while (1) { example.bit0 = cnt & (1 << 0)? true : false; example.bit1 = cnt & (1 << 1)? true : false; example.bit2 = cnt & (1 << 2)? true : false; example.bit3 = cnt & (1 << 3)? true : false; example.bit4 = cnt & (1 << 4)? true : false; if (example.bit4) example.bit5 = !example.bit5; cnt++; } }

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