На каких платформах есть что-то кроме 8-битного символа?

136

Время от времени кто-то на SO указывает, что char(иначе, «байт») не обязательно 8 бит .

Кажется, что 8-битный charпочти универсален. Я бы подумал, что для основных платформ необходимо иметь 8-битную версию, charчтобы обеспечить ее жизнеспособность на рынке.

И сейчас, и исторически, какие платформы используют charне 8 бит, и почему они отличаются от «обычных» 8 бит?

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

В прошлом я сталкивался с некоторыми ЦСП Analog Devices, для которых charэто 16 бит. Полагаю, что DSP - это немного нишевая архитектура. (Опять же, в то время, когда ассемблер с ручным кодированием легко справлялся с тем, что могли делать доступные компиляторы C, я не особо разбирался в C на этой платформе.)

Крейг МакКуин
источник
9
Серия CDC Cyber ​​имела 6/12-битное кодирование. Самые популярные персонажи были 6 бит. Остальные символы использовали 12 бит.
Томас Мэтьюз
2
PDP-11 прибил его. Представление о том, что символ может быть закодирован в символе, серьезно устарело.
Ганс Пассант
7
«PDP-11 прибил его» - Вы имеете в виду, потому что C был впервые реализован для PDP-11 с 8-битными байтами? Но затем C был реализован для машин Honeywell с 9-битными байтами. См. Версию 1 K & R. Кроме того, вопрос задавался о символе (то есть байте), а не о символе (один или несколько байтов, кодирующих то, о чем не спрашивалось).
Windows программист
6
DEC-10 и DEC-20 имели 36-битные слова. Пять 7-битных символов ASCII на слово было довольно распространенным явлением. Также были использованы шесть 6-битных символов.
Дэвид Р. Триббл
3
@CraigMcQueen: Если я правильно помню, микроконтроллеры CodeVision для Atmel позволяют выбрать размер символа
vsz

Ответы:

80

charтакже 16 бит на ЦСП Texas Instruments C54x, который появился, например, в OMAP2. Есть другие DSP с 16 и 32 битами char. Я думаю, что я даже слышал о 24-битном DSP, но я не могу вспомнить что, так что, возможно, я себе это представил.

Еще одним соображением является то, что POSIX мандаты CHAR_BIT == 8. Так что, если вы используете POSIX, вы можете принять это. Если кому-то позже понадобится перенести ваш код в почти внедренную POSIX, то случится так, что у вас будут функции, которые вы используете, но другого размера char, это их неудача.

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

Стив Джессоп
источник
2
DSP TI C62xx и C64xx также имеют 16-битные символы. (uint8_t не определен на этой платформе.)
myron-semack
7
Многие DSP для обработки аудио - это 24-битные машины; BelaSigna ЦСП от On Semi (после того, как они купили AMI пола); DSP56K / Symphony Audio ЦСП от Freescale (после того, как они были отделилась от Motorola).
Дэвид Кэри
2
У @msemack C64xx есть аппаратное обеспечение для 16.08.32/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-х годов предполагали, что конкретная задержка тактирования неактивных процессоров, занимающая фиксированное количество циклов, займет фиксированное количество тактовых импульсов, поскольку большинство потребительских процессоров были примерно эквивалентны по мощности. К сожалению, компьютеры стали быстрее очень быстро. Это привело к появлению коробок с кнопками «Турбо», цель которых, по иронии судьбы, состояла в том, чтобы замедлить работу компьютера, чтобы в игры, использующие технику задержки, можно было играть с разумной скоростью.


Один комментатор спросил, где в стандарте написано, что char должен иметь не менее 8 бит. Это в разделе 5.2.4.2.1 . Этот раздел определяет CHAR_BITколичество битов в наименьшем адресуемом объекте и имеет значение по умолчанию, равное 8. Он также говорит:

Их определяемые реализацией значения должны быть равны или больше по величине (абсолютное значение) показанным с тем же знаком.

Таким образом, любое число, равное 8 или выше, подходит для замены реализацией в CHAR_BIT.

Джон Феминелла
источник
6
Я не видел кнопки Turbo по крайней мере 20 лет - вы действительно думаете, что это уместно для вопроса?
Марк Рэнсом
29
@ Марк Рэнсом: В этом весь смысл. Разработчики часто полагаются на предположения, которые на данный момент кажутся верными, но гораздо более ненадежны, чем кажутся на первый взгляд. (Не могу сосчитать, сколько раз я совершил эту ошибку!) Кнопка «Турбо» должна быть болезненным напоминанием о том, чтобы не делать ненужных предположений и, конечно, не делать предположений, которые не гарантированы языковым стандартом, как если бы они были неизменные факты.
Джон Феминелла
1
Не могли бы вы указать, чтобы поместить в C ++ Standard, который говорит, что пока имеет по крайней мере 8 бит? Это общее убеждение, однако я лично не смог найти его в Стандарте. Единственное, что я нашел в Стандарте, это то, какие символы должны быть представлены charболее 64, но меньше 128, так что 7 бит будет достаточно.
Адам Бадура
6
Раздел 18.2.2 использует для этого стандарт Си. В стандарте C это раздел 7.10, а затем раздел 5.4.2.4.1. Страница 22 в стандарте C.
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,
R Самуэль Клатчко
источник
7
Также машины Honeywell, такие как, возможно, вторая машина, где был реализован C. См. Версию K & R 1.
Программист Windows,
5
На самом деле, декабрь-10 было также 6-битные символы - вы можете упаковать 6 из них в 36-разрядное слово (экс-декабря-10 программист Talking)
2
DEC-20 использовал пять 7-битных символов ASCII на 36-битное слово в TOPS-20 O / S.
Дэвид Р. Триббл
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: Я почти уверен, что для PDP-10 / DecSystem 10 / DecSystem 20. был хотя бы один (предстандартный) компилятор C, но я был бы очень удивлен компилятором C для мэйнфреймов CDC (они были использовался в основном для числовой работы, так что компилятор Фортрана был большой вещью там). Я уверен, что у других есть компиляторы Си.
Джерри Коффин
3
Разве компилятор Windows CE действительно не поддерживал этот charтип? Я знаю, что системные библиотеки поддерживали только широкие версии функций char, которые принимают строки, и что по крайней мере некоторые версии WinCE удалили строковые функции ANSI, такие как strlen, чтобы вы не выполняли обработку строк char. Но разве у него вообще не было типа char? Что было sizeof(TCHAR)? Какой тип возвратил malloc? Как byteреализован тип Java ?
Стив Джессоп
10
Windows CE поддерживает символ, который является байтом. См. Комментарий Крейга МакКуина к ответу Ричарда Пеннингтона. Байты нужны в Windows CE точно так же, как и везде, независимо от их размеров.
Программист Windows
2
Есть (были?) Как минимум две реализации C для PDP-10: KCC и порт gcc ( pdp10.nocrew.org/gcc ).
AProgrammer
3
Стандарт C не разрешает 7-битные символы, упакованные по 5 на 36-битное слово (как вы упомянули для PDP-10), и не допускает 6-битные символы, как вы упомянули для мэйнфреймов Control Data. См. Parashift.com/c++-faq-lite/intrinsic-types.html#faq-26.6
Кен Блум,
15

Нет такого понятия, как полностью переносимый код. :-)

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

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

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

Итак, вы уже многое сделали для достижения переносимости.

А теперь последний вопрос. У нас есть буфер. Данные с него отправляются в сеть TCP / IP. Такая сеть предполагает 8-битные байты. Вопрос в том, какого типа должен быть буфер? Если ваши символы 9-битные? Если они 16-битные? 24? Может быть, каждый символ соответствует одному 8-битному байту, отправленному в сеть, и используются только 8 бит? Или, может быть, несколько сетевых байтов упакованы в 24/16/9-битные символы? Это вопрос, и трудно поверить, что есть один ответ, который подходит для всех случаев. Многое зависит от реализации сокетов для целевой платформы.

Итак, о чем я говорю. Обычно код может быть относительно легко сделан переносимым в определенной степени . Это очень важно сделать, если вы планируете использовать код на разных платформах. Однако улучшение переносимости сверх этой меры - это то, что требует больших усилий и часто дает мало , поскольку реальный код почти всегда зависит от другого кода (реализация сокетов в приведенном выше примере). Я уверен, что для примерно 90% кода способность работать на платформах с байтами, отличными от 8-битных, практически бесполезна, поскольку она использует среду, привязанную к 8-битным. Просто проверьте размер байта и выполните утверждение времени компиляции. Вам почти наверняка придется много переписывать для очень необычной платформы.

Но если ваш код сильно «автономен» - почему бы и нет? Вы можете написать его так, чтобы он позволял разные размеры байтов.

Ellioh
источник
4
Если каждый хранит один октет на unsigned charзначение, проблем переносимости не должно быть, если в коде не используются трюки с алиасами, а не сдвиги для преобразования последовательностей октетов в / из больших целочисленных типов. Лично я считаю, что стандарт C должен определять встроенные функции для упаковки / распаковки целых чисел из последовательностей более коротких типов (наиболее типично char), хранящих фиксированное гарантированно доступное количество бит на элемент (8 на unsigned char, 16 на unsigned shortили 32 на unsigned long).
суперкат
9

Похоже, что вы все еще можете купить IM6100 (т.е. PDP-8 на чипе) со склада. Это 12-битная архитектура.

dmckee --- котенок экс-модератора
источник
9

Многие чипы DSP имеют 16- или 32-разрядные char. TI обычно делает такие чипы, например .

Алок Сингхал
источник
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

Определяет байт на этой машине, чтобы быть переменной длины

petantik
источник
1
«Не уверен насчет других языков» - исторически сложилось, что большинство языков позволяли архитектуре машины определять свой собственный размер в байтах. Исторически так было и в Си, пока стандарт не установил нижнюю границу на уровне 8.
Программист Windows,
4

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

PrgTrdr
источник
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или что - то другое. Большая часть тяжелой работы уже проделана людьми, которые написали ваши компилятор / стандартные библиотеки.

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

ВТА
источник
2
Вопрос не задавался о символах (будь то Unicode или нет). Он спросил о символе, который является байтом.
Программист 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 бита в другом месте .....

если каждый uchar содержит «битовые флаги», а каждый uchar имеет только 2 «значимых» бита или флага, которые вы в настоящее время используете, и вы только организовали их в 3 uchars для «ясности», то это может быть относительно «более расточительным», например, на платформа с 24-битными учарами .....

ничто битовое поле не может решить, но у них есть другие вещи, на которые стоит обратить внимание ....

в этом случае, только одно перечисление может быть способом получения «наименьшего» целого числа, которое вам действительно нужно ....

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

просто тот факт, что если uchar в три раза больше того, что "обычно" ожидается, 100 таких структур могут тратить много памяти на некоторых платформах ..... где "обычно" это не имеет большого значения .... ,

так что все еще можно «сломать» или в этом случае «очень быстро потратить много памяти» из-за предположения, что uchar «не очень расточительно» на одной платформе по сравнению с доступной оперативной памятью, чем на другой платформе ... ..

проблема может быть более заметной, например, для целых чисел или других типов, например, у вас есть структура, которая требует 15 битов, поэтому вы помещаете ее в int, но на какой-то другой платформе int составляет 48 бит или что-то еще .... ,

«обычно» вы можете разбить его на 2 учара, но, например, с 24-битным учаром вам понадобится только один .....

так что enum может быть лучшим "общим" решением ....

зависит от того, как вы получаете доступ к этим битам, хотя :)

таким образом, могут быть "недостатки дизайна", которые поднимают их голову .... даже если код все еще может работать / работать нормально независимо от размера uchar или uint ...

есть такие вещи, на которые стоит обратить внимание, хотя в вашем коде нет «магических чисел» ...

надеюсь, что это имеет смысл :)

дд е
источник
1
...какие? Как вы думаете, почему enumон может быть меньше, чем другие нативные типы? Вы знаете, что по умолчанию используется то же хранилище, что и int? «у вас есть какая-то структура, которая требует 15 битов, поэтому вы помещаете ее в int, но на какой-то другой платформе int составляет 48 бит или что-то еще .....» - так что #include <cstdint>сделайте это int16_tдля лучшей возможности минимизации использования битов , Я действительно не уверен, что вы думали, что говорили среди всех этих эллипсов.
underscore_d
1

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

8-битные символы уже являются чем-то вроде анахронизма. Нам уже нужно 32 бита для хранения всех наборов символов мира.

Ричард Пеннингтон
источник
2
Правда. Название charнемного странное в дни Юникода. Меня больше волнует 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-битным, но это не совсем так. Обратите внимание, что они на самом деле больше не печатают таблицы полного кода.
Просфилаес