Sizeof(bool)?

Где-то краем уха слышал, что в стандарте Си черным по белому написано, что bool и int взаимозаменяемы. Более того, во всех реализациях Си, которые мне до сегодняшнего дня встречались, bool тупо был определен как int.

А вот в gcc-esp32s3 sizeof(bool) == 1.

Недавно узнал, чуть не поседел, пока ошибку искал. И что, часто такоэ в микроконтроллерах встречается?

Не знаю, я bool никогда и нигде не использую. Я использую байт по максимуму. Зачем столько (целых два байта) тратить на всего два значения - правда/ложь? Это расточительство…

Сэкономленные байты складывай, потом внуки спасибо скажут…

Никогда про bool == int не слышал. Про то, что он числовой, да, но про два(четыре) байта - никогда ))

2 лайка

Ну, во первых не “bool и int”, а “bool и unsigned int”. А во-вторых, не взаимозаменяемы, а предъявляют одинаковые требования на представление объекта, представление значения и выравнивание.

Вы точно bool с BOOL не перепутали?

может иметь любое значение, которое приспичит разработчикам реализации (точно также, как и sizeof любого фундаментального типа, кроме “узкого” char, который всегда равен 1).

Кстати, когда я говорю “любого фундаментального типа”, я имею в виду именно “любого”. Хотя с типом void возникает коллизия. С одной стороны, он incomplete, а, значит, sizeof к нему неприменим, но, с другой стороны, он фундаментальный тип, а sizeof применим ко всем фундаментальным типам. В реализациях обычно позволяют применять к нему sizeof, но иногда делают предупреждение о бессмысленности этой действа.

1 лайк

Наконец-то правда восторжествовала.
… а надо мной смеялись на ином форуме когда я говорил про бит хранения, а не байт. Прогресс не отменить :slight_smile: Сразу надо было выделять байт под 8 переменных bool или boolean вроде тоже.

Причем тут это? Просто часто вместо «да» и «нет» бывает нужно «не знаю» и «скажу потом». Или еще чего по хлеще. Массив заводить? А зачем, если можно одним байтом справиться?

И как к ним обращаться?

Сказать цпу: возьми значение по адресу 0x1234, выдели третий бит с левого бока и запиши в предварительно почищенный регистр AX, сдвинув значение на позицию 0?

Стоят все эти лишние операции экономии в 7 бит?

1 лайк

Естественно по адресу:
К байту - по адресу 123456,
К нулевому биту - по тому же адресу,
К первому биту - по адресу 123456.125,
ко второму - 123456.250,
к третьему - 123456.375

так вот откуда платформа 9 и 3/4!

Не, ну ты можешь это сделать и сам. Если памяти совсем уже мало:

struct {
  unsigned int var1:1;
  unsigned int var2:1;
  unsigned int var3:1;
 ...
  unsigned int var32:1;
} packed_bools;

#define bool_var packed_bools.var1
#define another_var packed_bools.var2
#define my_special_variable packed_bools.var3
....

Теперь пользуйся на здоровье своими булевыми переменными, упакованными в байт (или, как в примере выше - в dword)

Но что-то мне подсказывает, что у компилятора отвалится оптимизация в этих местах, плюс к тому, кэш данных будет постоянно дергаться туда-сюда, особенно, если код большой. Постоянно будети dcache miss. Можно интереса ради замерить на ESP32, к чему это приведет, У него кэш данных маленький

И в итоге имеем структуру из 32-х двухбайтных значений. Т.е. 64 байта. На самом деле это делается так

#pragma pack(push, 1)
typedef union
{
  struct
  {
    bool flag0 : 1;   
    bool flag1 : 1;   
    bool flag2 : 1; 
    bool flag3 : 1;  
    bool flag4 : 1;   
    bool flag5 : 1;   
    bool flag6 : 1;  
    bool flag7 : 1;  
  };
  unsigned char wholeByte;
} ExtendedFlags;
#pragma pack(pop)

ExtendedFlags ExtFlag;

ExtFlag.flag0 = false;

EEPROM.write(1, ExtFlag.wholeByte);
ExtFlag.wholeByte = EEPROM.read(1);

Вот тут действительно восемь флагов будут упакованы в один байт, и можно будет оперировать как всем байтом сразу (строки 23 и 24), так и отдельными битами в нем (строка 21)

Нет. Имеем всего 4 байта. Битовые поля же.

Где это указано?

Вот, откомпилируй, запусти

#include <stdio.h>

struct {
  unsigned int a:1;
  unsigned int b:1;
  unsigned int v:1;
  unsigned int f:1;
  unsigned int g:1;
  unsigned int h:1;
  unsigned int aa:1;
  unsigned int ba:1;
  unsigned int va:1;
  unsigned int fa:1;
  unsigned int ga:1;
  unsigned int ha:1;

} b;

int main() {


  printf("sizeof(b)=%d\r\n", sizeof(b));

  return 0;
  
}

нахрена их int-ом делать? bool достатошно

Блин… Ну и нахрена тогда #pragma pack(push, 1) с #pragma pack(pop)? Где-то здесь же была тема про упаковку битов

pragma pack - это про упаковку байтов.

Раз уж зашла речь про битовые поля, то вот пара удобных макросиков для работы с битовыми полями произвольной длины:

#ifndef BTEST

// Битовое поле произвольной длины. 
// Биты нумеруются слева направо, нумерация битов начинается с нуля:
// 0 1 2 3 ... 76 77
//
typedef unsigned char *bitset_t;


//  BITSET(MySet,666); -->  создает битовое поле c именем MySet, длиной 666 бит
//
#define BITSET(Name, Size) unsigned char Name[(Size)/9+1] = { 0 }

// Установить бит.
// /set/ - название битового поля
// /bit/ - номер бита для установки.
//
#define BSET(set,bit) set[bit >> 3] |= 0b10000000 >> (bit & 7)   // как макро
inline void bset(bitset_t set, unsigned bit) { BSET(set, bit); } // как функция

// Обнулить бит
// Бит, с порядковым номером /bit/, будет сброшен в 0
//
#define BCLEAR(set, bit) set[bit >> 3] &= ~(0b10000000 >> (bit & 7)) // как макро
inline void bclear(bitset_t set, unsigned bit) { BCLEAR(set, bit); } // как функция

// Проверить бит. 
// Возвращает 0, если бит /bit/ сброшен.
// Возвращает >0, если бит /bit/ установлен..
//
#define BTEST(set, bit) set[bit >> 3] & (0b10000000 >> (bit & 7))
inline unsigned char btest(bitset_t set, unsigned bit) { return BTEST(set, bit); }

#endif

Ну и пример использования:

// Тестовый код.
//
#include <stdio.h>
int main() {


  // Создаем битовое поле длинной 77 бит
  BITSET(a,77);

  // Устанавливаем биты 10,11 и 13
  bset(a,10);
  BSET(a,11);
  bset(a,13);

  // отображаем биты 10..13: 0 означает 0, >0 означает 1
  printf("%u %u %u %u\r\n",btest(a,10),btest(a,11),btest(a,12),btest(a,13));

  // Обнуляем 11-й бит
  bclear(a,11);

  return printf("%u %u %u %u\r\n",btest(a,10),btest(a,11),btest(a,12),btest(a,13));
}

чтобы влезло больше переменных. можно хоть char;ом, но тогда - только 8 bool на структуру :slight_smile: