Почему логическое значение имеет размер 1 байт, а не 1 бит?


127

В C ++

  • Почему логическое значение имеет размер 1 байт, а не 1 бит?
  • Почему нет таких типов, как 4-битные или 2-битные целые числа?

Я упускаю перечисленное выше при написании эмулятора для процессора


10
В C ++ вы можете «упаковать» данные, используя битовые поля. struct Packed { unsigned int flag1 : 1; unsigned int flag2: 1; };, Большинство компиляторов выделяют полный unsigned int, однако они сами справляются с перестановкой битов при чтении / записи. Также они работают сами по себе с операциями по модулю. Это unsigned small : 4атрибут имеет значение от 0 до 15, и когда оно должно стать равным 16, он не будет перезаписывать предыдущий бит :)
Мэтью М.

Ответы:


208

Потому что ЦП не может обращаться ни к чему меньше байта.


10
Черт, теперь это неловко, сэр
Асм

31
На самом деле, четыре x86 инструкции bt, bts, btrи btc могут обратиться одиночные биты!
fredoverflow 07

11
Я думаю, btадрес байтового смещения, а затем проверка бит с заданным смещением, независимо от того, при указании адреса, который вы вводите в байтах ... литералы смещения бит будут немного многословными (извините за каламбур).
user7116 07

2
@six: вы можете загрузить начало массива в один регистр, а затем относительное «битовое смещение» во второй. Битовое смещение не ограничено «в пределах одного байта», это может быть любое 32-битное число.
fredoverflow 07

4
Ну да и нет. У нас есть битовые поля, и мы могли бы иметь указатель битового поля, то есть адрес + номер бита. Очевидно, что такой указатель не может быть преобразован в void * из-за дополнительных требований к памяти для номера бита.
Максим Егорушкин

32

Из Википедии :

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

Таким образом, байт - это основная адресуемая единица , ниже которой компьютерная архитектура не может обращаться. И поскольку (вероятно) не существует компьютеров, поддерживающих 4-битные байты, у вас нет 4-битных bool и т. Д.

Однако, если вы можете спроектировать такую ​​архитектуру, которая может адресовать 4-битную как базовую адресуемую единицу, тогда у вас будет bool4-битный размер только на этом компьютере!


4
«тогда у вас будет int размером 4 бита только на этом компьютере» - нет, не будет, потому что стандарт запрещает CHAR_BIT быть меньше 8. Если адресуемая единица в архитектуре меньше 8 бит, тогда Реализация C ++ просто должна будет представить модель памяти, которая отличается от модели памяти основного оборудования.
Стив Джессоп

@ Стив: ой ... Я не заметил этого. Удалено intи charиз моего поста.
Nawaz

1
у вас также не может быть 4-битного bool, потому что charэто наименьшая адресуемая единица в C ++ , независимо от того, что архитектура может адресовать с помощью собственных кодов операций. sizeof(bool)должен иметь значение не менее 1, а соседние boolобъекты должны иметь свои собственные адреса в C ++ , поэтому реализация просто должна увеличить их и тратить память. Вот почему битовые поля существуют как особый случай: элементы битового поля структуры не обязательно должны иметь отдельную адресацию, поэтому они могут быть меньше, чем char(хотя вся структура по-прежнему не может быть).
Стив Джессоп

@ Стив Джессоп: это кажется интересным. не могли бы вы дать мне ссылку из спецификации языка, где говорится, charчто это наименьшая адресуемая единица в C ++?
Nawaz

3
ближайшим конкретным утверждением, вероятно, является 3.9 / 4: «Объектное представление объекта типа T - это последовательность из N объектов типа char без знака, принимаемых объектом типа T, где N равно sizeof (T)». Очевидно, sizeof(bool)не может быть 0,5 :-) Я полагаю, что реализация может на законных основаниях предоставлять суббайтовые указатели в качестве расширения, но «обычные» объекты, такие как bool, выделяемые обычным образом, должны делать то, что говорит стандарт.
Стив Джессоп

12

Самый простой ответ: это потому, что ЦП адресует память в байтах, а не в битах, а побитовые операции выполняются очень медленно.

Однако в C ++ можно использовать распределение битового размера. Для битовых векторов существует специализация std :: vector, а также структуры, принимающие записи битового размера.


1
Не уверен, что согласен с тем, что побитовые операции выполняются медленно. ands, nots, xors и т. д. очень быстрые. Обычно это медленная реализация побитовых операций. На машинном уровне они довольно быстрые. Ветвление ... теперь это медленно.
Hogan

3
Чтобы было понятнее, если вы создадите вектор логических значений и поместите в него 24 логических значения, он будет занимать только 3 байта (3 * 8). Если вы введете другое логическое значение, он займет еще один байт. Тем не менее, если вы нажмете другое логическое значение, оно не займет никаких дополнительных байтов, потому что оно использует «свободные» биты в последнем байте
Педро Лоурейро

да, я тоже сомневаюсь, что операции идут медленно :)
Педро Лоурейро

Битовые векторы не создают выделения битового размера. они создают выделения размером в байты. Невозможно выделить ни одного бита.
Джон Диблинг

1
Чтение одного бита в битовом векторе требует трех операций: сдвига и, и еще одного сдвига. Написание - два. Тогда как к отдельным байтам можно получить доступ с помощью одного.
sukru 07

7

В былые времена, когда мне приходилось идти в школу в бушующую метель, подниматься в обе стороны, и обедать было какое бы животное мы ни могли выследить в лесу за школой и убить голыми руками, у компьютеров было гораздо меньше доступной памяти, чем Cегодня. Первый компьютер, который я когда-либо использовал, имел 6 КБ ОЗУ. Не 6 мегабайт, не 6 гигабайт, 6 килобайт. В этой среде имело смысл упаковать в int столько логических значений, сколько вы могли, и поэтому мы регулярно использовали операции для их извлечения и вставки.

Сегодня, когда люди будут издеваться над вами за то, что у вас всего 1 ГБ ОЗУ, а единственное место, где вы можете найти жесткий диск с объемом менее 200 ГБ, - это антикварный магазин, просто не стоит тратить силы на то, чтобы упаковывать биты.


За исключением случаев с флагами. Такие вещи, как установка нескольких параметров для чего-либо ... например. 00000001 + 00000100 = 00000101.
Armstrongest

@Atomix: Я почти никогда этим не занимаюсь. Если мне нужно два флага, я создаю два логических поля. Раньше я писал код, в котором я упаковывал такие флаги, а затем писал «if flags & 0x110! = 0 then» и т.п., но это непонятно, и в наши дни я обычно делаю отдельные поля и пишу «if fooFlag || barFlag "вместо этого. Я не исключаю возможность случаев, когда упаковка таких флагов по какой-то причине лучше, но больше не нужно экономить память, как раньше.
Джей

2
На самом деле, это вполне стоит вашей беды упаковать бит, если вы хотите , чтобы ваши вычисления , чтобы быть быстрым - на этом большом количестве данных , которые хранятся в памяти. Упаковка логических значений предназначена не только для меньшего хранилища - это означает, что вы можете читать свои логические входные массивы в 8 раз быстрее (с точки зрения пропускной способности), чем когда они распакованы, и это часто довольно важно. Кроме того, вы можете использовать битовые операции, такие как popc (подсчет населения), которые ускоряют вашу работу на самом процессоре.
einpoklum

2
Поистине огромное количество логических значений - это то, с чем вы работаете каждый день, если вы это делаете: СУБД, машинное обучение, научное моделирование и множество других вещей. И - просто работать с ними - значит копировать их - из памяти в кеш. Миллионы булов - это ничто, подумайте о миллиардах.
einpoklum

1
@PeterCordes Да, безусловно, если бы у меня был набор логических значений, которые логически были «той же идеей», так что я, естественно, думал о них как о «массиве» в некотором смысле, и если бы я затем собирался их замаскировать или отфильтровать, или в противном случае выполнять с ними побитовые операции, тогда упаковка их в байты может иметь смысл. Как я сказал ранее, мне трудно вспомнить, когда я последний раз работал над приложением, в котором применялись эти условия, но вы приведете пару хороших примеров, и я уверен, что с небольшим воображением можно было бы подумать о других.
Джей

6

Вы можете использовать битовые поля для получения целых чисел субразмера.

struct X
{
    int   val:4;   // 4 bit int.
};

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

struct SomThing   // 1 byte value (on a system where 8 bits is a byte
{
    int   p1:4;   // 4 bit field
    int   p2:3;   // 3 bit field
    int   p3:1;   // 1 bit
};

6

У вас могут быть 1-битные логические значения и 4- и 2-битные целые числа. Но это привело бы к странному набору инструкций без увеличения производительности, потому что это неестественный взгляд на архитектуру. На самом деле имеет смысл «потратить впустую» лучшую часть байта, а не пытаться вернуть неиспользуемые данные.

По моему опыту, единственное приложение, которое пытается упаковать несколько bool в один байт, - это Sql Server.


6

Потому что байт - это наименьшая адресуемая единица языка.

Но вы можете сделать так, чтобы bool занимал 1 бит, например, если у вас их несколько, например. в структуре, например:

struct A
{
  bool a:1, b:1, c:1, d:1, e:1;
};

2

boolможет быть одним байтом - наименьшим адресуемым размером ЦП или может быть больше. Нет ничего необычного в том, boolчтобы быть размером с intдля повышения производительности. Если для определенных целей (например, для моделирования оборудования) вам нужен тип с N битами, вы можете найти для этого библиотеку (например, у библиотеки GBL есть BitSet<N>класс). Если вас беспокоит размер bool(у вас, вероятно, большой контейнер), вы можете упаковать биты самостоятельно или использовать std::vector<bool>это для вас (будьте осторожны с последним, поскольку он не удовлетворяет требованиям к контейнеру).


2

Подумайте, как бы вы реализовали это на своем уровне эмулятора ...

bool a[10] = {false};

bool &rbool = a[3];
bool *pbool = a + 3;

assert(pbool == &rbool);
rbool = true;
assert(*pbool);
*pbool = false;
assert(!rbool);

2

Потому что, как правило, ЦП выделяет память с 1 байтом в качестве базовой единицы, хотя некоторые ЦП, такие как MIPS, используют 4-байтовое слово.

Однако vectorработает boolособым образом, с vector<bool>выделением одного бита для каждого логического значения.


1
Я считаю, что даже процессор MIPS предоставит вам доступ к отдельному байту, хотя это снижает производительность.
Пол Томблин

@Paul: Да, вы правы, но в целом слово " lw/" swиспользуется гораздо шире.
Райан Ли

Не знаю о MIPS, но архитектура IA-64 разрешает доступ только на 64-битной границе.
Гена Бушуев

0

Байт - это меньшая единица хранения цифровых данных компьютера. В компьютере ОЗУ состоит из миллионов байтов, и у любого из них есть адрес. Если бы у него был адрес для каждого бита, компьютер мог бы управлять оперативной памятью в 8 раз меньше, чем он может.

Более подробная информация: Википедия.


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.