Время от времени кто-то на SO указывает, что char
(иначе, «байт») не обязательно 8 бит .
Кажется, что 8-битный char
почти универсален. Я бы подумал, что для основных платформ необходимо иметь 8-битную версию, char
чтобы обеспечить ее жизнеспособность на рынке.
И сейчас, и исторически, какие платформы используют char
не 8 бит, и почему они отличаются от «обычных» 8 бит?
Когда вы пишете код и думаете о кроссплатформенной поддержке (например, для библиотек общего пользования), какое внимание стоит уделить платформам с не-8-битной архитектурой char
?
В прошлом я сталкивался с некоторыми ЦСП Analog Devices, для которых char
это 16 бит. Полагаю, что DSP - это немного нишевая архитектура. (Опять же, в то время, когда ассемблер с ручным кодированием легко справлялся с тем, что могли делать доступные компиляторы C, я не особо разбирался в C на этой платформе.)
источник
Ответы:
char
также 16 бит на ЦСП Texas Instruments C54x, который появился, например, в OMAP2. Есть другие DSP с 16 и 32 битамиchar
. Я думаю, что я даже слышал о 24-битном DSP, но я не могу вспомнить что, так что, возможно, я себе это представил.Еще одним соображением является то, что POSIX мандаты
CHAR_BIT == 8
. Так что, если вы используете POSIX, вы можете принять это. Если кому-то позже понадобится перенести ваш код в почти внедренную POSIX, то случится так, что у вас будут функции, которые вы используете, но другого размераchar
, это их неудача.В целом, однако, я думаю, что почти всегда легче обойти эту проблему, чем думать об этом. Просто введите
CHAR_BIT
. Если вы хотите точный 8-битный тип, используйтеint8_t
. Ваш код с шумом не сможет скомпилироваться в реализациях, которые его не предоставляют, вместо того, чтобы молча использовать размер, который вы не ожидали. По крайней мере, если я столкнусь с делом, в котором у меня были веские основания полагать, что это так, то я бы это утверждал.источник
assert()
(если ты это имел в виду) я бы использовал#if CHAR_BIT != 8
...#error "I require CHAR_BIT == 8"
...#endif
static_assert()
?Дело не столько в том, что «стоит задумываться» о чем-то, сколько об играх по правилам. Например, в C ++ стандарт говорит, что все байты будут иметь «как минимум» 8 бит. Если ваш код предполагает, что байты имеют ровно 8 бит, вы нарушаете стандарт.
Сейчас это может показаться глупым - « конечно, все байты имеют 8 бит!», Я слышал, вы говорите. Но многие очень умные люди полагались на предположения, которые не были гарантиями, и тогда все сломалось. История изобилует такими примерами.
Например, большинство разработчиков начала 90-х годов предполагали, что конкретная задержка тактирования неактивных процессоров, занимающая фиксированное количество циклов, займет фиксированное количество тактовых импульсов, поскольку большинство потребительских процессоров были примерно эквивалентны по мощности. К сожалению, компьютеры стали быстрее очень быстро. Это привело к появлению коробок с кнопками «Турбо», цель которых, по иронии судьбы, состояла в том, чтобы замедлить работу компьютера, чтобы в игры, использующие технику задержки, можно было играть с разумной скоростью.
Один комментатор спросил, где в стандарте написано, что char должен иметь не менее 8 бит. Это в разделе 5.2.4.2.1 . Этот раздел определяет
CHAR_BIT
количество битов в наименьшем адресуемом объекте и имеет значение по умолчанию, равное 8. Он также говорит:Таким образом, любое число, равное 8 или выше, подходит для замены реализацией в
CHAR_BIT
.источник
char
более 64, но меньше 128, так что 7 бит будет достаточно.Машины с 36-битной архитектурой имеют 9-битные байты. Согласно Википедии, машины с 36-битной архитектурой включают в себя:
источник
Несколько из которых я знаю:
источник
char
тип? Я знаю, что системные библиотеки поддерживали только широкие версии функций char, которые принимают строки, и что по крайней мере некоторые версии WinCE удалили строковые функции ANSI, такие как strlen, чтобы вы не выполняли обработку строк char. Но разве у него вообще не было типа char? Что былоsizeof(TCHAR)
? Какой тип возвратил malloc? Какbyte
реализован тип Java ?Нет такого понятия, как полностью переносимый код. :-)
Да, могут быть различные размеры байтов / символов. Да, могут быть реализации 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-битным. Просто проверьте размер байта и выполните утверждение времени компиляции. Вам почти наверняка придется много переписывать для очень необычной платформы.
Но если ваш код сильно «автономен» - почему бы и нет? Вы можете написать его так, чтобы он позволял разные размеры байтов.
источник
unsigned char
значение, проблем переносимости не должно быть, если в коде не используются трюки с алиасами, а не сдвиги для преобразования последовательностей октетов в / из больших целочисленных типов. Лично я считаю, что стандарт C должен определять встроенные функции для упаковки / распаковки целых чисел из последовательностей более коротких типов (наиболее типичноchar
), хранящих фиксированное гарантированно доступное количество бит на элемент (8 наunsigned char
, 16 наunsigned short
или 32 наunsigned long
).Похоже, что вы все еще можете купить IM6100 (т.е. PDP-8 на чипе) со склада. Это 12-битная архитектура.
источник
Многие чипы DSP имеют 16- или 32-разрядные
char
. TI обычно делает такие чипы, например .источник
Цитируется с http://en.wikipedia.org/wiki/Byte#History
Не уверен насчет других языков, хотя.
http://en.wikipedia.org/wiki/IBM_7030_Stretch#Data_Formats
Определяет байт на этой машине, чтобы быть переменной длины
источник
Семейство DEC PDP-8 имело 12-битное слово, хотя вы обычно использовали 8-битный ASCII для вывода (в основном на Teletype). Тем не менее, был также 6-битный код символа, который позволял вам кодировать 2 символа в одном 12-битном слове.
источник
Во-первых, символы 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
.источник
магические числа возникают, например, при смещении;
большинство из них могут быть обработаны довольно просто с помощью CHAR_BIT и, например, UCHAR_MAX вместо 8 и 255 (или аналогичных).
надеюсь, ваша реализация определяет их :)
это "общие" вопросы .....
другая косвенная проблема - скажем, у вас есть:
это может «только» занять (в лучшем случае) 24 бита на одной платформе, но может занять, например, 72 бита в другом месте .....
если каждый uchar содержит «битовые флаги», а каждый uchar имеет только 2 «значимых» бита или флага, которые вы в настоящее время используете, и вы только организовали их в 3 uchars для «ясности», то это может быть относительно «более расточительным», например, на платформа с 24-битными учарами .....
ничто битовое поле не может решить, но у них есть другие вещи, на которые стоит обратить внимание ....
в этом случае, только одно перечисление может быть способом получения «наименьшего» целого числа, которое вам действительно нужно ....
возможно, не реальный пример, но такие вещи "кусают" меня при портировании / воспроизведении некоторого кода .....
просто тот факт, что если uchar в три раза больше того, что "обычно" ожидается, 100 таких структур могут тратить много памяти на некоторых платформах ..... где "обычно" это не имеет большого значения .... ,
так что все еще можно «сломать» или в этом случае «очень быстро потратить много памяти» из-за предположения, что uchar «не очень расточительно» на одной платформе по сравнению с доступной оперативной памятью, чем на другой платформе ... ..
проблема может быть более заметной, например, для целых чисел или других типов, например, у вас есть структура, которая требует 15 битов, поэтому вы помещаете ее в int, но на какой-то другой платформе int составляет 48 бит или что-то еще .... ,
«обычно» вы можете разбить его на 2 учара, но, например, с 24-битным учаром вам понадобится только один .....
так что enum может быть лучшим "общим" решением ....
зависит от того, как вы получаете доступ к этим битам, хотя :)
таким образом, могут быть "недостатки дизайна", которые поднимают их голову .... даже если код все еще может работать / работать нормально независимо от размера uchar или uint ...
есть такие вещи, на которые стоит обратить внимание, хотя в вашем коде нет «магических чисел» ...
надеюсь, что это имеет смысл :)
источник
enum
он может быть меньше, чем другие нативные типы? Вы знаете, что по умолчанию используется то же хранилище, что иint
? «у вас есть какая-то структура, которая требует 15 битов, поэтому вы помещаете ее в int, но на какой-то другой платформе int составляет 48 бит или что-то еще .....» - так что#include <cstdint>
сделайте этоint16_t
для лучшей возможности минимизации использования битов , Я действительно не уверен, что вы думали, что говорили среди всех этих эллипсов.Интервал был 16 бит (pdp11 и т. д.). Переход на 32-битные архитектуры был трудным. Людям становится лучше: вряд ли кто-то полагает, что указатель будет соответствовать длинному (вы не правы?). Или смещение файла, или отметки времени, или ...
8-битные символы уже являются чем-то вроде анахронизма. Нам уже нужно 32 бита для хранения всех наборов символов мира.
источник
char
немного странное в дни Юникода. Меня больше волнует 8-битные единицы (октеты) при работе с двоичными данными, например, для хранения файлов, сетевых коммуникаций.uint8_t
более полезно.