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 Размещение битовых полей структуры в памяти, режим big-endian. Используйте директиву #pragma bitfields=disjoint_types, чтобы принудительно разъединить контейнеры битовых полей, или другими словами, сделать так, чтобы контейнеры не перекрывались. В этом случае структура вышеуказанного примера будет выглядеть так: Размещение битовых полей структуры в памяти, режим 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) { 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; Очевидно, что код получается компактнее и проще для понимания. Однако это еще не все - проверка показала, что размер кода с битовыми полями иногда получается даже меньше, чем кода с использованием масок. |