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

Время от времени кто-то на ТАК отмечает, что char (иначе "байт") не обязательно 8 бит.

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

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

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

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

14 ответов

Решение

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

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

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

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

Дело не столько в том, что "стоит задумываться" о чем-то, сколько об играх по правилам. Например, в C++ стандарт говорит, что все байты будут иметь "как минимум" 8 бит. Если ваш код предполагает, что байты имеют ровно 8 бит, вы нарушаете стандарт.

Теперь это может показаться глупым - "конечно, все байты имеют 8 бит!", Я слышал, вы говорите. Но многие очень умные люди полагались на предположения, которые не были гарантиями, и тогда все сломалось. История изобилует такими примерами.

Например, большинство разработчиков начала 90-х годов предполагали, что конкретная задержка тактирования неактивных процессоров, занимающая фиксированное количество циклов, займет фиксированное количество тактового времени, потому что большинство потребительских процессоров были примерно эквивалентны по мощности. К сожалению, компьютеры стали быстрее очень быстро. Это привело к появлению коробок с кнопками "Турбо", цель которых, по иронии судьбы, состояла в том, чтобы замедлить работу компьютера, чтобы в игры, использующие технику задержки, можно было играть с разумной скоростью.


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

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

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

Машины с 36-битной архитектурой имеют 9-битные байты. Согласно Википедии, машины с 36-битной архитектурой включают в себя:

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

Несколько из которых я знаю:

  • 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

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

Да, могут быть различные размеры байтов / символов. Да, могут быть реализации 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-битным. Просто проверьте размер байта и выполните утверждение времени компиляции. Вам почти наверняка придется много переписывать для очень необычной платформы.

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

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

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

Например, языки программирования 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

Не уверен насчет других языков, хотя.

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

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

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

какое внимание стоит уделить платформам с не-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...

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

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

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

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

Изменить: Извините, я изначально неправильно понял ваш вопрос.

В спецификации C сказано, что char Объект "достаточно большой, чтобы хранить любой элемент набора символов выполнения". limits.h перечисляет минимальный размер 8 бит, но определение оставляет максимальный размер char открыть.

Таким образом, 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,

Самым странным, что я видел, были компьютеры CDC. 6-битные символы, но с 65 кодировками. [Также было более одного набора символов - вы выбираете кодировку при установке ОС.]

Если слово из 60 заканчивалось 12, 18, 24, 30, 36, 40 или 48 битами нуля, это был символ конца строки (например, '\n').

Поскольку символ 00 (восьмеричный) был : в некоторых кодовых наборах это означало, что BNF использовал ::=было неудобно, если он попал не в тот столбец. [Это задолго до C++ и других распространенных способов использования ::.]

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

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

Серия Univac 1100 имела два режима работы: 6-битные FIELDATA и 9-битный ASCII, упакованные 6 или 4 символа соответственно в 36-битные слова. Вы выбираете режим во время выполнения программы (или во время компиляции). Прошло много лет с тех пор, как я действительно работал над ними.

Другие вопросы по тегам