Чому булевий 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
Чорт, зараз це незручно, сер
Asm

31
На насправді, чотири x86 інструкції bt, bts, btrі btc можуть звернутися поодинокі біти!
fredoverflow

11
Я думаю, що btадресує байтове зміщення, а потім тестує біт у заданому зміщенні, незалежно від того, коли вказувати адресу, яку ви вводите в байти ... Біт-літерали зміщення отримають трохи багатослівний (вибачте за каламбур).
user7116

2
@six: Ви можете завантажити початок масиву в один реєстр, а потім відносне "бітове зміщення" в секунду. Зсув бітів не обмежується "в межах одного байта", це може бути будь-яке 32-бітове число.
fredoverflow

4
Ну так і ні. У нас є бітфілди, і ми можемо мати вказівник бітфілда, тобто адресу + бітове число. Очевидно, що такий покажчик не був би конвертованим у недійсний * через додаткову вимогу зберігання бітового числа.
Максим Єгорушкін

32

З Вікіпедії :

Історично байт - це кількість біт, що використовуються для кодування одного символу тексту на комп'ютері, і саме тому є основним адресованим елементом у багатьох архітектурах комп'ютерів.

Так байти основна адресується одиниця , нижче якої комп'ютерна архітектура не може вирішити. А оскільки не існує (ймовірно) комп'ютерів, які підтримують 4-бітний байт, у вас немає 4-бітових і т.д. bool

Однак якщо ви можете спроектувати таку архітектуру, яка може адресувати 4-розрядну базу як основний адресний блок, тоді ви матимете boolрозмір 4-розрядний лише на цьому комп'ютері!


4
"у вас буде розмір int розміру 4-розрядний тоді, лише на цьому комп'ютері" - ні, ви не будете, тому що стандарт забороняє CHAR_BIT бути менше 8. Якщо адресний блок в архітектурі менше 8 біт, то a Реалізація C ++ просто повинна представити модель пам'яті, яка відрізняється від основної моделі пам'яті апаратури.
Стів Джессоп

@Steve: oops ... Я це не помітив. Видалено intі charз моєї посади.
Наваз

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

@ Стів Джессоп: це здається цікавим. Ви можете, будь ласка, надати мені посилання з мовної специфікації, де сказано, що charце найменша адресна одиниця в C ++?
Наваз

3
Найближче конкретне твердження, ймовірно, становить 3,9 / 4: "Об'єктне представлення об'єкта типу T - це послідовність N неподписаних символів char, взятих об'єктом типу T, де N дорівнює sizeof (T)". Очевидно, що sizeof(bool)не може бути 0,5 :-) Я думаю, що реалізація могла б законодавчо надавати підбайтові покажчики як розширення, але "звичайні" об'єкти, такі як bool, виділяються звичайними способами, повинні робити те, що говорить стандарт.
Стів Джессоп

12

Найпростіша відповідь; це тому, що ЦП звертається до пам'яті в байтах, а не в бітах, а бітові операції дуже повільні.

Однак можливо використовувати розподіл розміру бітів у C ++. Існує std :: векторна спеціалізація для бітових векторів, а також структури, що приймають записи розміру біт.


1
Не впевнений, я погодився б, що побітні операції проходять повільно. ands, nots, xors тощо дуже швидко. Зазвичай це виконання побітових операцій, які є повільними. На рівні машини вони досить швидкі. Відгалуження ... тепер це повільно.
Хоган

3
Щоб зробити це більш зрозумілим, якщо ви створите вектор булевих і вкладете в нього 24 булевих, буде потрібно лише 3 байти (3 * 8). Якщо ви помістите інший булевий, він займе ще один байт. Тим не менш, якщо ви натиснете інший булевий, він не займе зайвих байтів, оскільки він використовує "безкоштовні" біти в останньому байті
Педро Лурейро

так, я також сумніваюсь, що операції з укусом уповільнені :)
Педро Лурейро

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

1
Читання одного біта в бітовому векторі вимагає трьох операцій: shift і, і ще один зсув знову. Писати два. Тоді як до окремих байтів можна отримати доступ з одним.
sukru

7

Ще в старі часи, коли мені доводилося ходити до школи в бурхливій хуртовині, в гору обох напрямках, а обід був будь-якою твариною, яку ми могли б відшукати в лісі за школою та вбити голими руками, у комп’ютерів було набагато менше пам’яті, ніж сьогодні. Перший комп'ютер, який я коли-небудь використовував, мав 6К ОЗУ. Не 6 мегабайт, не 6 гігабайт, 6 кілобайт. У цьому середовищі було багато сенсу упакувати якомога більше булів в інт, і ми могли б регулярно використовувати операції, щоб вивезти їх і помістити.

Сьогодні, коли люди знущаються з вас за те, що ви маєте лише 1 ГБ оперативної пам’яті, і єдине місце, де ви могли б знайти жорсткий диск із меншими за 200 ГБ, - це антикварний магазин, просто не варто клопотати, щоб пакувати біти.


За винятком випадків, коли стосується прапорів. Такі речі, як встановлення кількох варіантів на щось ... наприклад. 00000001 + 00000100 = 00000101.
Армстронгст

@Atomix: Я майже ніколи цього не роблю. Якщо мені потрібні два прапори, я створюю два булевих поля. Раніше я писав код, куди я би упакував такі прапори, а потім писав "якщо прапори & 0x110! = 0 тоді" або подібне, але це загадковим чином, і в ці дні я зазвичай роблю окремі поля і пишу "якщо 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-бітні вставки. Але це призвело б до отримання дивного набору інструкцій без підвищення продуктивності, оскільки це неприродний спосіб дивитися на архітектуру. Насправді має сенс "витрачати" більшу частину байти, а не намагатися відновити невикористані дані.

На моєму досвіді єдиний додаток, який турбує запакувати кілька булів в один байт, - це сервер Sql.


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>цьому виділяється по одному біту на кожен bool.


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

@Paul: Так, ти маєш рацію, але загалом слово-специфічні lw/ swнабагато ширше використовуються.
Райан Лі

Не знаєте про MIPS, але архітектура IA-64 дозволяє отримати доступ лише на 64-бітних кордонах.
Гена Бушуєва

0

Байт - це менша одиниця зберігання цифрових даних комп'ютера. У комп'ютері оперативна пам’ять має мільйони байтів, і кожен з них має адресу. Якби у нього була адреса для кожного біта, комп'ютер міг би керувати у 8 разів менше оперативної пам’яті, ніж те, що може.

Більше інформації: Вікіпедія


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.