Які платформи мають щось інше, ніж 8-бітний графік?


136

Час від часу хтось із SO зазначає, що char(також "байт") не обов'язково 8 біт .

Здається, що 8-бітний charмайже універсальний. Я б подумав, що для основних платформ необхідно мати 8-розрядний, charщоб забезпечити його життєздатність на ринку.

Зараз і історично, які платформи використовують a, charщо не є 8 бітами, і чому вони відрізняються від "нормальних" 8 біт?

Коли ви пишете код і думаєте про підтримку крос-платформ (наприклад, для бібліотек загального користування), яке врахування варто приділити платформам, які не є 8-бітними char?

Раніше я стикався з деякими ЦАП аналогових пристроїв, для яких char16 біт. DSP - це трохи нішева архітектура. (Знову ж таки, під час ручного кодування асемблер легко обіграв те, що могли зробити наявні компілятори C, тому я не мав особливого досвіду роботи з C на цій платформі.)


9
Серія CDC Cyber ​​мала кодування 6/12 біт. Найпопулярнішими персонажами було 6 біт. Решта символів використовувала 12 біт.
Томас Меттьюз

2
PDP-11 прибив її. Поняття про те, що персонаж може бути закодований у картці, є серйозно застарілим.
Ганс Пасант

7
"PDP-11 прибив її" - Ви маєте на увазі, оскільки C вперше був реалізований для PDP-11 з 8-бітовими байтами? Але C був в подальшому реалізований для машин Honeywell з 9 бітовими байтами. Дивіться K&R версії 1. Також питання про char (тобто байт), а не про символи (один або кілька байтів, що кодують те, про що не запитували).
програміст Windows

6
DEC-10 і DEC-20 мали 36-бітні слова. П'ять 7-бітних символів ASCII на слово були досить поширеними. Також було використано шість 6-бітових символів.
David R Tribble

3
@CraigMcQueen: Якщо я добре пам’ятаю, мікроконтролери CodeVision для Atmel дозволяють вибрати розмір char
vsz

Відповіді:


80

charтакож є 16 бітним на DSP Texas Instruments C54x, який з'явився, наприклад, в OMAP2. Є інші DSP з 16 і 32 біт char. Я думаю, що я навіть чув про 24-розрядний DSP, але не можу пригадати що, тому, можливо, я уявив це.

Інша думка полягає в тому, що POSIX мандати CHAR_BIT == 8. Тож якщо ви використовуєте POSIX, ви можете це припустити. Якщо хтось пізніше повинен перенести ваш код до майже реалізованої POSIX, у вас просто так є функції, які ви використовуєте, але іншого розміру char, це їхня невдача.

Взагалі, однак, я думаю, що майже завжди простіше вирішити проблему, ніж думати над цим. Просто введіть CHAR_BIT. Якщо ви хочете ввести точний 8-бітний тип, використовуйте int8_t. Ваш код шумно не зможе скомпілюватись у реалізаціях, які не забезпечують його, замість того, щоб тихо використовувати розмір, який ви не очікували. Принаймні, якби я потрапив у випадок, коли у мене були вагомі підстави припустити це, то я б це запевнив.


2
TI C62xx і C64xx DSP також мають 16-бітні символи. (uint8_t не визначено на цій платформі.)
myron-semack

7
Багато DSP для обробки аудіо - це 24-бітні машини; BelaSigna ЦСП від On Semi (після того, як вони купили AMI статі); DSP56K / Symphony Audio ЦСП від Freescale (після того, як вони були відокремилася від Motorola).
Девід Кері

2
У @msemack C64xx є обладнання для 16.08.34/40 та 8-
бітний

4
Замість того, щоб assert()(якщо це саме ви мали на увазі), я б використав #if CHAR_BIT != 8... #error "I require CHAR_BIT == 8"...#endif
Кіт Томпсон,

1
@KeithThompson Чи є причина не використовувати static_assert()?
Qix - МОНІКА ПОМИЛИЛА

37

Коли ви пишете код і думаєте про підтримку крос-платформ (наприклад, для бібліотек загального користування), яку саме увагу варто приділити платформам, які не мають 8-бітових знаків?

Справа не стільки в тому, що "варто врахувати" щось, як це грає за правилами. Наприклад, у C ++ стандарт каже, що всі байти матимуть "принаймні" 8 біт. Якщо ваш код передбачає, що в байтах рівно 8 біт, ви порушуєте стандарт.

Зараз це може здатися дурним - " звичайно, всі байти мають 8 біт!" Але багато дуже розумних людей покладалися на припущення, які не були гарантіями, і тоді все зламалось. Історія рясніє такими прикладами.

Наприклад, більшість розробників на початку 90-х припускали, що певна затримка синхронізованого процесора з фіксованою кількістю циклів потребуватиме фіксованого часу, оскільки більшість споживчих процесорів були приблизно однаковою за потужністю. На жаль, комп’ютери стали дуже швидкими. Це породило підйом ящиків за допомогою кнопок "Turbo" - мета яких, за іронією долі, полягала в тому, щоб уповільнити роботу комп'ютера, щоб ігри, що використовують техніку затримки часу, могли грати з розумною швидкістю.


Один коментатор запитав, де в стандарті йдеться про те, що char повинен мати принаймні 8 біт. Це в розділі 5.2.4.2.1 . Цей розділ визначає CHAR_BITкількість бітів у найменшій адресованій сутності та має значення за замовчуванням 8. Тут також зазначено:

Значення, визначені їх реалізацією, повинні бути рівними або більшими за величиною (абсолютне значення) показаним, з однаковим знаком.

Отже, будь-яке число, рівне 8 або більше, підходить для заміни реалізацією в CHAR_BIT.


6
Я не бачив кнопки Turbo принаймні 20 років - ти справді вважаєш, що це невідповідність питання?
Марк Рансом

29
@Mark Ransom: У цьому вся суть. Розробники часто покладаються на припущення, які на даний момент здаються істинними, але які набагато хиткіші, ніж вони спочатку здаються. (Неможливо підрахувати, скільки разів я зробив , що помилка!) Кнопка Turbo повинна бути болючим нагадуванням не робити непотрібні припущення, і , звичайно , не робити припущення, що не гарантується стандартом мови , як якщо б вони були незмінні факти.
Джон Фемінелла

1
Не могли б ви вказати, щоб розмістити в стандарті C ++, який говорить, що бай має принаймні 8 біт? Це загальноприйнята думка, проте мені особисто не вдалося знайти його у Стандарті. Єдине, що я знайшов у Standard - це те, які символи повинні бути представленими, charїх налічується більше 64, але менше, ніж 128, тож вистачить 7 біт.
Адам Бадура

6
Розділ 18.2.2 посилається на стандарт С для нього. У стандарті C це розділ 7.10, а потім розділ 5.4.2.4.1. Сторінка 22 у стандарті С.
програміст Windows

2
Тож інші відповіді та коментарі згадують машини з 5-бітовим, 6-бітним та 7-бітовим байтами. Це означає, що ви не можете запустити програму C на тій машині, яка відповідає стандарту?
Джеррі Єремія

34

Машини з 36-бітовою архітектурою мають 9-бітні байти. За даними Вікіпедії, машини з 36-бітовою архітектурою включають:

  • Корпорація цифрового обладнання PDP-6/10
  • IBM 701/704/709/7090/7094
  • UNIVAC 1103 / 1103A / 1105/1100/2200,

7
Також машини Honeywell, такі як, можливо, друга машина, де реалізовано C. Дивіться K&R версії 1.
Програміст Windows

5
Насправді, у Декаду 10 було також 6-розрядних символів - ви можете спакувати 6 з них у 36-розрядне слово (колишній програвач, який розмовляв 10 грудня)

2
DEC-20 використовував п'ять 7-бітних символів ASCII на 36-бітове слово на TOPS-20 O / S.
David R Tribble

3
Цей жарт був реально реалізований для підтримки Unicode в цій архітектурі.
Джошуа

9
Я думаю, що причина восьми восьми колись фактично використовувалася через те, що 3 восьмеричні цифри акуратно представляють 9-бітовий байт, подібно до того, як ми зазвичай сьогодні використовуємо шістнадцятковий, оскільки дві шістнадцяткові цифри акуратно представляють 8-бітний байт.
bames53

18

Кілька з яких мені відомо:

  • DEC PDP-10: змінна, але найчастіше 7-бітні символи упаковані 5 на 36-бітове слово, або ж 9-бітні символи, 4 на слово
  • Основні рамки керування даними (CDC-6400, 6500, 6600, 7600, Cyber ​​170, Cyber ​​176 тощо) 6-бітні символи, упаковані 10 на 60-бітове слово.
  • Основні рамки Unisys: 9 біт / байт
  • Windows CE: просто не підтримує тип `char` - натомість потрібен 16-розрядний wchar_t

2
@ephemient: Я впевнений, що принаймні один (передстандартний) компілятор C для PDP-10 / DecSystem 10 / DecSystem 20. був би дуже здивований компілятором C для мейнфреймів CDC, хоча (вони були використовувався в основному для чисельної роботи, тому компілятор Fortran був тут великою справою). Я впевнений, що в інших є компілятори C.
Джеррі Труну

3
Чи компілятор Windows CE насправді взагалі не підтримував цей charтип? Я знаю, що системні бібліотеки підтримували лише широкі версії char функцій, які беруть рядки, і що принаймні деякі версії WinCE видаляли функції рядка ANSI, як strlen, щоб перешкодити вам виконувати обробку рядків char. Але хіба це насправді взагалі не було типового статусу? Що було sizeof(TCHAR)? Якого типу повернувся малок? Як був byteреалізований тип Java ?
Стів Джессоп

10
Windows CE підтримує char, який є байтом. Дивіться коментар Крейга МакКуїна на відповідь Річарда Пеннінгтона. Байти потрібні стільки ж в Windows CE, скільки і скрізь, незалежно від того, які розміри вони є скрізь.
програміст Windows

2
Існують (були?) Щонайменше дві реалізації C для PDP-10: KCC та порт gcc ( pdp10.nocrew.org/gcc ).
AProgrammer

3
Стандарт C не дозволить 7-бітовим символам упаковано 5 на 36-бітове слово (як ви згадували для PDP-10), а також не дозволить 6-бітових символів, як ви згадували для мейнфреймів Control Data Control. Дивіться parashift.com/c++-faq-lite/intrinsic-types.html#faq-26.6
Ken Bloom

15

Немає такого поняття, як повністю портативний код. :-)

Так, можуть бути різні розміри байтів / знаків. Так, для платформ із вкрай незвичайними значеннями CHAR_BITта і може бути реалізація C / C ++ UCHAR_MAX. Так, іноді можна написати код, який не залежить від розміру char.

Однак майже будь-який реальний код не є самостійним. Наприклад, ви можете писати код, який надсилає двійкові повідомлення в мережу (протокол не важливий). Ви можете визначити структури, які містять необхідні поля. Чим вам доведеться це серіалізувати. Просто бінарне копіювання структури у вихідний буфер не є портативним: як правило, ви не знаєте ні байтового порядку для платформи, ні членів структури вирівнювання, тому структура просто зберігає дані, але не описує спосіб серіалізації даних. .

Гаразд. Ви можете виконувати перетворення порядку байтів і переміщувати елементи структури (наприклад, uint32_tабо подібні), використовуючи memcpyв буфер. Чому memcpy? Тому що існує дуже багато платформ, на яких неможливо записати 32-бітну (16-бітну, 64-бітну - немає різниці), коли цільова адреса не вирівняна належним чином.

Отже, ви вже багато зробили для досягнення портативності.

І ось остаточне питання. У нас буфер. Дані з нього надсилаються до мережі TCP / IP. Така мережа передбачає 8-бітні байти. Питання: якого типу буфера повинен бути? Якщо ваші символи 9-бітні? Якщо вони 16-бітні? 24? Можливо, кожен char відповідає одному 8-бітовому байту, надісланому в мережу, і використовується лише 8 біт? А може кілька байтів мережі упаковані в 24/16/9-бітні символи? Це питання, і важко повірити, що є одна відповідь, яка підходить для всіх випадків. Багато речей залежить від реалізації сокета для цільової платформи.

Отже, про що я говорю. Зазвичай код може бути досить легко переносимим певною мірою . Це дуже важливо, якщо ви очікуєте використання коду на різних платформах. Однак покращення портативності поза цим показником - це справа, яка вимагає великих зусиль і часто дає мало зусиль , оскільки реальний код майже завжди залежить від іншого коду (реалізація сокета в прикладі вище). Я впевнений, що приблизно 90% кодової здатності працювати на платформах, окрім 8-бітових байтів, майже марно, оскільки вона використовує середовище, пов'язане з 8-бітовим. Просто перевірте розмір байтів і виконайте затвердження часу компіляції. Вам майже напевно доведеться багато переписати для надзвичайно незвичної платформи.

Але якщо ваш код сильно "автономний" - чому б і ні? Ви можете записати його таким чином, що дозволяє різні розміри байтів.


4
Якщо зберігається один октет на unsigned charзначення, не повинно виникнути проблем з переносом, якщо код не використовує псевдонімічні трюки, а не зсуви для перетворення послідовностей октетів у / з більших цілих типів. Особисто я вважаю, що стандарт C повинен визначати властивості упаковки / розпакування цілих чисел із послідовностей коротших типів (найчастіше char), зберігаючи фіксовану гарантовано доступну кількість біт на елемент (8 за unsigned char, 16 за unsigned shortабо 32 за unsigned long).
supercat



5

Наприклад, мови програмування C і C ++ визначають байт як "адресується одиниця даних, достатньо велика, щоб вмістити будь-якого члена основного набору символів середовища виконання" (п. 3.6 стандарту C). Оскільки інтегральний тип даних C char повинен містити щонайменше 8 біт (п. 5.2.4.2.1), байт у C може принаймні вміщати 256 різних значень. Різні реалізації C і C ++ визначають байт як 8, 9, 16, 32 або 36 біт

Цитується з http://en.wikipedia.org/wiki/Byte#History

Хоча не впевнений в інших мовах.

http://en.wikipedia.org/wiki/IBM_7030_Stretch#Data_Formats

Визначає байт на цій машині, який має змінну довжину


1
"Не впевнений в інших мовах" - історично більшість мов дозволило архітектурі машини визначити свій власний розмір байтів. Насправді історично це робилося на C, поки стандарт не встановив нижню межу в 8.
Програміст Windows

4

Сім'я DEC PDP-8 мала 12-бітове слово, хоча ви зазвичай використовували 8-бітний ASCII для виводу (в основному для телетайпу). Однак був також 6-бітний код символів, який дозволив кодувати 2 символи в одному 12-бітному слові.


3

Для одного символи Unicode довші, ніж 8-бітні. Як згадував хтось раніше, специфікація C визначає типи даних за їх мінімальними розмірами. Використовуйте sizeofта значення, limits.hякщо ви хочете допитати свої типи даних та дізнатись, який саме розмір вони мають для вашої конфігурації та архітектури.

З цієї причини я намагаюся дотримуватися типів даних, наприклад, uint16_tколи мені потрібен тип даних певної довжини бітів.

Редагувати: Вибачте, я спочатку неправильно прочитав ваше запитання.

Специфікація C говорить, що charоб'єкт "досить великий, щоб зберігати будь-який член набору символів виконання". limits.hперелічує мінімальний розмір 8 біт, але визначення залишає максимальний розмір charвідкритим.

Таким чином, a charє щонайменше до тих пір, поки найбільший символ із набору виконання вашої архітектури (як правило, округлюється до найближчої 8-бітної межі). Якщо у вашій архітектурі є довші опкоди, ваш charрозмір може бути довшим.

Історично опкод платформи x86 був одним байтом, тому charспочатку було 8-бітним значенням. Поточні платформи x86 підтримують опкоди довші, ніж один байт, але цей charвміст зберігається у довжині 8 біт, оскільки саме цим обумовлені програмісти (та великі обсяги існуючого коду x86).

Розмірковуючи про підтримку багатоплатформ, скористайтеся типами, визначеними в stdint.h. Якщо ви використовуєте (наприклад) в uint16_t, то ви можете бути впевнені , що це значення без знака 16-розрядне значення , на якій архітектурі, будь то 16-бітове значення відповідає char, short, intабо що - то інше. Більшість важкої роботи вже зроблено людьми, які написали ваш компілятор / стандартні бібліотеки.

Якщо вам потрібно знати точний розмір, charтому що ви виконуєте апаратні маніпуляції низького рівня, які вимагають цього, я зазвичай використовую тип даних, який є досить великим, щоб вмістити charна всіх підтримуваних платформах (як правило, достатньо 16 біт) і запустити значення через convert_to_machine_charрутину, коли мені потрібно точне представлення машини. Таким чином, специфічний для платформи код обмежений функцією інтерфейсу і більшу частину часу я можу використовувати звичайний uint16_t.


2
Питання не задавало символів (Unicode чи ні). Тут розпитували про char, що є байтом.
програміст Windows

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

"Історично опис платформи x86 був одним байтом": як солодко. Історично C розроблявся на PDP-11 (1972), задовго до того, як було винайдено x86 (1978).
Мартін Боннер підтримує Моніку

3

Яке врахування варто приділити платформам, які не мають 8-бітових знаків?

магічні числа виникають, наприклад, при зміщенні;

більшість із них можна обробити досить просто, використовуючи CHAR_BIT і, наприклад, UCHAR_MAX замість 8 та 255 (або подібних).

сподіваємось, ваша реалізація визначає це :)

це "загальні" питання .....

Інше непряме питання - це те, що у вас є:

struct xyz {
   uchar baz;
   uchar blah;
   uchar buzz; 
}

це може «брати» лише (найкращий випадок) 24 біти на одній платформі, але може брати, наприклад, 72 біти в іншому місці .....

якщо кожен учар містив "бітові прапори", а кожен учар мав лише 2 "значущі" біти або прапори, якими ви користуєтесь в даний час, і ви лише організували їх у 3 схеми для "ясності", то це може бути відносно "більш марнотратним", наприклад, на платформа з 24-бітними uchars .....

ніщо бітфілд не може вирішити, але у них є інші речі, на які слід стежити ...

у цьому випадку лише один перерахунок може бути способом отримати найменше ціле число, яке вам потрібно.

можливо, не справжній приклад, але такі речі, як це "покусали" мене при перенесенні / програванні з деяким кодом .....

лише той факт, що якщо учар втричі більший, ніж очікується, "100 таких" очікується, 100 таких структур можуть витратити багато пам'яті на деяких платформах ... там, де "нормально", це не велика справа .... .

тому все ще можна "зламати" або в цьому випадку "витратити багато пам'яті дуже швидко" через припущення, що uchar "не дуже марнотратний" на одній платформі, відносно наявної оперативної пам'яті, ніж на іншій платформі ... ..

проблема може бути більш помітною, наприклад, для int або інших типів, наприклад, у вас є якась структура, якій потрібно 15 біт, тому ви вставляєте її в int, але на іншій платформі int становить 48 біт або що завгодно .... .

"нормально", ви можете розбити його на 2 рівні, але, наприклад, з 24-бітним учаром вам знадобиться лише один .....

тож перерахунок може бути кращим "загальним" рішенням ....

залежить від того, як ви отримуєте доступ до цих бітів :)

тож, можуть виникнути "недоліки дизайну", які затримують голову .... навіть якщо код все ще може працювати / працювати нормально, незалежно від розміру учара чи уті ...

є такі речі, на які слід дивитися, хоча у вашому коді немає жодних "магічних чисел" ...

сподіваюся, що це має сенс :)


1
...що? Чому, на вашу думку enum, ймовірно, він буде меншим, ніж інші рідні типи? Чи знаєте ви, що він за замовчуванням відповідає тому ж сховищу, що і int? "у вас є структура, якій потрібно 15 біт, тому ви вставляєте її в int, але на іншій платформі int - 48 біт або що завгодно ....." - так #include <cstdint>і зробіть це int16_tнайкращим шансом мінімізувати використання бітів. . Я справді не впевнений, що ти думав, що ти говориш серед усіх цих еліпсів.
підкреслити_

1

ints раніше було 16 біт (pdp11 тощо). Перейти до 32-бітної архітектури було важко. Люди стають кращими: навряд чи хтось припускає, що вказівник більше не поміститься (ви не так?). Або файлові зсуви, або часові позначки, або ...

8-бітові символи вже є дещо анахронізмом. Нам вже потрібно 32 біти, щоб вмістити всі набори символів у світі.


2
Правда. У charдні Unicode ця назва трохи причудлива. Я більше дбаю про 8-бітові одиниці (октети) під час роботи з бінарними даними, наприклад, зберігання файлів, мережеві комунікації. uint8_tкорисніше.
Крейг МакКуїн

3
Насправді Unicode ніколи не потребував повних 32 біт. Спочатку вони планувались на 31 (див. Оригінальну роботу UTF-8), але зараз вони задовольняються лише 21 бітом . Вони, напевно, зрозуміли, що більше не зможуть надрукувати книгу, якщо їм справді знадобляться всі 31 біт: P
me22

2
@ me22, Unicode спочатку планувався на 16 біт. "Символи Unicode послідовно ширяються 16 біт, незалежно від мови ..." Unicode 1.0.0. unicode.org/versions/Unicode1.0.0/ch01.pdf .
Шеннон Северанс

1
Спочатку ISO 10646 був 31 біт, а Unicode об'єднався з ISO 10646, тому можна сказати, що Unicode - 31 біт, але це насправді неправда. Зверніть увагу, вони вже не друкують повні таблиці кодів.
профілі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.