Создание программы, переносимой между машинами с разным количеством бит в "машинный байт",

Мы все любим портативные программы C/С++.

Мы знаем, что sizeof(char) или sizeof(unsigned char) всегда 1 "байт". Но этот 1 "байт" не означает байт с 8 битами. Это просто означает "машинный байт", а количество бит в нем может отличаться от машины к машине. См. этот вопрос.


Предположим, вы выписали букву ASCII 'A' в файл foo.txt. На любой нормальной машине в эти дни, которая имеет 8-разрядный машинный байт, эти биты будут записаны:

01000001

Но если бы вы запускали тот же код на машине с 9-битным машинным байтом, я предполагаю, что эти биты будут записаны:

001000001

Более того, последняя машина могла записать эти 9 бит как один машинный байт:

100000000

Но если бы мы прочитали эти данные на прежней машине, мы бы не смогли это сделать должным образом, так как места недостаточно. Так или иначе, мы должны сначала прочитать один машинный байт (8 бит), а затем каким-то образом преобразовать окончательный 1 бит в 8 бит (машинный байт).


Как программисты могут правильно согласовать эти вещи?

Я прошу, что у меня есть программа, которая пишет и читает файлы, и я хочу убедиться, что она не сломается через 5, 10, 50 лет.

Ответ 1

Как программисты могут правильно согласовать эти вещи?

Ничего не делая. Вы представили проблему с файловой системой.

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

Чтобы гарантировать, что компилятор C/С++ может обоснованно существовать для этого компьютера, эта новая компьютерная ОС соответствует тем же стандартам, что и C и С++, где файлы имеют размер, измеренный в байтах.

... У вас уже есть небольшая проблема с вашим 8-битным исходным кодом. Там только около 1-в-9 случай, каждый исходный файл является размером, который может даже существовать в этой системе.

Или, может быть, нет. Как часто бывает для меня, Johannes Schaub - litb имеет превентивно цитирует стандарт относительно допустимых форматов исходного кода на С++.

Изображения физического исходного файла отображаются в определяемый реализацией, базовому набору символов источника (ввод символов новой строки для индикаторов конца строки), если необходимо. Последовательности триграфа (2.3) заменяются соответствующими односимвольные внутренние представления. Любой символ исходного файла а не в базовом наборе символов (2.2) заменяется на имя универсального символа, которое опознает этот символ. (An реализация может использовать любое внутреннее кодирование, если фактическое расширенный символ, встречающийся в исходном файле, и тот же расширенный символ, выраженный в исходном файле как имя универсального символа (т.е. с использованием обозначения \uXXXX), обрабатываются что то же самое.)

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

Итак, здесь, где твоя настоящая проблема. Если создатели этого компьютера были достаточно любезны, чтобы предоставить утилиту для расширения 8-битных ASCII файлов, чтобы они могли быть фактически сохранены на этой новой машине, уже нет проблемы с буквой ASCII A, которую вы написали давно. И если такой утилиты нет, то ваша программа уже нуждается в техническом обслуживании, и ничего не удалось сделать для ее предотвращения.

Изменить: более короткий ответ (адресация комментариев, которые с тех пор были удалены)

Вопрос задает вопрос о том, как работать с 9-разрядным компьютером ...

  • С аппаратным обеспечением, которое не имеет 8-битных инструкций с обратной совместимостью
  • С операционной системой, которая не использует "8-битные файлы".
  • С компилятором C/С++, который ломает, как программы на C/С++ имеют исторически написанные текстовые файлы.

Дамиан Конвей имеет часто повторяющуюся цитату, сравнивающую С++ с C:

"С++ пытается охранять Мерфи, а не Макиавелли".

Он описывал других инженеров-программистов, а не инженеров-аппаратов, но намерение по-прежнему звучит, потому что рассуждения одинаковы.

Оба C и С++ стандартизированы таким образом, чтобы вы предполагали, что другие инженеры хотят играть хорошо. Ваш Maciavellian компьютер не является угрозой для вашей программы, потому что это угроза для C/С++ полностью.

Возвращаясь к вашему вопросу:

Как программисты могут правильно согласовать эти вещи?

У вас действительно есть два варианта.

  • Примите, что описанный вами компьютер не подходит в мире C/С++
  • Принять, что C/С++ не подходит для программы, которая может запускаться на описываемом вами компьютере.

Ответ 2

Единственный способ убедиться, что это хранить данные в текстовых файлах, цифры как строки числовых символов, а не некоторое количество бит. XML, использующий UTF-8 и base 10, должен быть довольно хорошим общим выбором для переносимости и удобочитаемости, поскольку он хорошо определен. Если вы хотите быть параноидальным, держите XML достаточно простым, так что он может быть легко проанализирован простым пользовательским парсером, если реальный синтаксический анализатор XML не будет легко доступен для вашего гипотетического компьютера.

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

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

Если у вас есть определенный числовой диапазон, сохраните диапазон, чтобы вы могли явно проверить, соответствуют ли они доступным числовым типам данных.

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

Добавление фактического ответа:

  • В коде C, не обрабатывайте байт-буферы, за исключением изолированных функций, которые затем изменяются в зависимости от архитектуры процессора. Например, функции обработки JPEG могли бы либо структурировать обертку данных изображения неопределенным способом, либо имя файла для чтения изображения, но никогда не буферизованный буфер char* в байт.
  • Оберните строки в контейнер, который не предполагает кодирование (предположительно, он будет использовать UTF-8 или UTF-16 на 8-битной байт-машине, возможно, в настоящее время нестандартный UTF-9 или UTF-18 на 9-битном байте и т.д.).
  • Оберните все чтения из внешних источников (сеть, файлы на диске и т.д.) в функции, возвращающие собственные данные.
  • Создайте код, в котором не происходит целых переполнений, и не полагайтесь на поведение переполнения в любом алгоритме.
  • Определите бит-бит all-ones, используя ~0 (вместо 0xFFFFFFFF или что-то еще)
  • Предпочитают номера с плавающей точкой IEEE для большинства числовых хранилищ, где integer не требуется, поскольку они не зависят от архитектуры процессора.
  • Не хранить постоянные данные в двоичных файлах, которые вам, возможно, придется преобразовать. Вместо этого используйте XML в UTF-8 (который можно преобразовать в UTF-X, не нарушая ничего, для собственной обработки) и хранить числа как текст в XML.
  • То же, что и с разными байтовыми ордерами, за исключением, кроме того, только для того, чтобы быть уверенным в том, что вы переносите свою программу на реальную машину с различным количеством бит и выполняете всесторонние тесты. Если это действительно важно, вам, возможно, придется сначала реализовать такую ​​виртуальную машину, а также C-компилятор портов и необходимые библиотеки для него, если вы не можете найти их в противном случае. Даже тщательный (= дорогой) обзор кода займет у вас только часть пути.

Ответ 3

если вы планируете писать программы для Quantum Computers (которые будут доступны в ближайшем будущем для нас, чтобы купить), затем начните изучение квантовой физики и возьмите класс по их программированию.

Если вы планируете логическую логику компьютера в ближайшем будущем, тогда... мой вопрос: как вы убедитесь, что доступная сегодня файловая система не будет завтра? или как файл, хранящийся с 8-битным двоичным кодом, останется переносимым в файловых системах завтра?

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

Моя проблема заключается в том, что компьютерная система, которую я запрограммировал несколько лет назад, больше не существует (Motorola 68000) для нормальной публики, и программа сильно полагалась на машинный порядок байтов и ассемблера. Больше не переносится: - (

Ответ 4

Если вы говорите о написании и чтении двоичных данных, не беспокойтесь. Сегодня нет гарантии переносимости, кроме данных, которые вы пишете из своей программы, может быть прочитана программой той же, скомпилированной с помощью компилятора того же (включая параметры командной строки). Если вы говорите о написании и чтении текстовых данных, не беспокойтесь. Он работает.

Ответ 5

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

Во-вторых: я не думаю, что вам нужно беспокоиться об этом, потому что единственное реалистичное решение для запуска 8-битных программ на 9-битной машине (или аналогичной) - через Виртуальные машины.

Весьма вероятно, что любой человек в ближайшем или отдаленном будущем с использованием какой-либо 9-битной машины сможет запустить старую виртуальную машину x86/arm и запустить вашу программу таким образом. У аппаратного устройства через 25-50 лет не должно возникнуть проблем с тем, чтобы запустить все виртуальные машины только ради выполнения одной программы; и эта программа, вероятно, по-прежнему будет загружать, выполнять и выключать быстрее, чем сегодня, на текущем 8-битном аппаратном уровне. (сегодня некоторые облачные сервисы уже имеют тенденцию к запуску целых ВМ только для обслуживания отдельных задач)

Я сильно подозреваю, что это единственное средство, с помощью которого любая 8-битная программа будет запускаться на машинах с 9/другими битами из-за точек, сделанных в других ответах относительно основных проблем, присущих простому загрузке и анализу 8-разрядных исходный код или 8-битные двоичные исполняемые файлы.

Он не может быть удаленно похож на "эффективный", но он будет работать. Это также предполагает, конечно, что у VM будет некоторый механизм, посредством которого 8-битные текстовые файлы могут быть импортированы и экспортированы с виртуального диска на главный диск.

Как вы можете видеть, это огромная проблема, которая выходит далеко за рамки исходного кода. Суть в том, что, скорее всего, будет намного дешевле и проще обновлять/модифицировать или даже повторно реализовывать с нуля вашу программу на новом оборудовании, а не пытаться объяснить такие неясные проблемы с переносимостью, фронт. Акт учета для него почти наверняка требует больше усилий, чем просто преобразования форматов дисков.

Ответ 6

8-битные байты останутся до конца, поэтому не потейте. Будут новые типы, но этот базовый тип никогда не изменится.

Ответ 7

Поздно, но я не могу противостоять этому. Прогнозировать будущее сложно. Предсказание будущего компьютеров может быть более опасным для вашего кода, чем преждевременная оптимизация.

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

Я ожидаю, что будущие проблемы с переносимостью будут связаны с оборудованием, имеющим минимум 16 или 32-битный доступ, что делает CHAR_BIT не менее 16. Тщательный дизайн здесь может помочь с любыми неожиданными 9-битными байтами.

QUESTION для читателей /.: кто-нибудь знает о процессорах общего назначения в производстве сегодня, используя 9-битные байты или одну арифметику дополнения? Я вижу, где могут существовать встроенные контроллеры, но не более того.

Длительный ответ
Еще в 1990-х годах глобализация компьютеров и Unicode заставила меня ожидать, что UTF-16 или больше будет управлять расширением бит-за-символом: CHAR_BIT в C. Но поскольку наследие переживает все, что я также ожидаю, 8-битные байты оставаться промышленным стандартом для выживания, по крайней мере, до тех пор, пока компьютеры используют двоичный файл.

BYTE_BIT: бит-за-байт (популярный, но не стандарт, который я знаю)
BYTE_CHAR: байты на символ

Стандарт C не адресует char потребление нескольких байтов. Он допускает это, но не обращается к нему.

3,6 байт: (окончательный проект стандарт C11 ISO/IEC 9899: 201x)
адресная единица хранения данных, достаточно большая, чтобы удерживать любого члена базового набора символов среды исполнения.

ПРИМЕЧАНИЕ 1: Можно однозначно выразить адрес каждого отдельного байта объекта.

ПРИМЕЧАНИЕ 2. Байт состоит из непрерывной последовательности бит, число которой определяется реализацией. Наименее значащий бит называется младшим битом; самый старший бит называется старшим битом.

Пока стандарт C не определяет, как обрабатывать значения BYTE_CHAR больше одного, и я не говорю о "широких символах", этот переносимый код основного фактора должен адресоваться, а не более крупные байты. Существующие среды, где CHAR_BIT составляет 16 или 32, - это то, что нужно изучать. Процессоры ARM - один из примеров. Я вижу два основных режима для чтения внешних потоков байтов, которые разработчикам необходимо выбрать:

  • Unpacked: один символ BYTE_BIT в локальный символ. Остерегайтесь расширений расширений.
  • Упакован: прочитайте байты BYTE_CHAR в локальный символ.

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

  #define BYTE_BIT 8                     // bits-per-byte
  #define BYTE_CHAR (CHAR_BIT/BYTE_BIT)  //bytes-per-char

  size_t byread(void  *ptr,
                size_t size,     // number of BYTE_BIT bytes
                int    packing,  // bytes to read per char
                                 // (negative for sign extension)
                FILE  *stream);

  size_t bywrite(void  *ptr,
                size_t size,
                int    packing,
                FILE  *stream);
  • size количество байтов BYTE_BIT для передачи.
  • packing для передачи на символ char. Обычно, как 1 или BYTE_CHAR, он может указывать BYTE_CHAR внешней системы, которая может быть меньше или больше текущей системы.
  • Никогда не забывайте о столкновениях со стороны Континента.

Хорошее исключение для 9-битных систем:
Мой предыдущий опыт написания программ для 9-битных сред заставляет меня поверить, что мы больше не увидим этого, если вам не понадобится программа для работы в реальной старой унаследованной системе где-нибудь. Вероятно, в 9-bit VM в 32/64-битной системе. Начиная с 2000 года я иногда делаю быстрый поиск, но не видел ссылок на текущие потомки старых 9-битных систем.

Любые, неожиданно, на мой взгляд, будущие 9-разрядные компьютеры общего назначения, вероятно, либо будут иметь 8-битный режим, либо 8-разрядную виртуальную машину (@jstine) для запуска программ. Единственное исключение - это встроенные процессоры специального назначения, которые в любом случае вряд ли будут работать с кодом общего назначения.

В течение нескольких лет одной 9-разрядной машиной был PDP/15. Десятилетие борьбы с клоном этого зверя заставляет меня никогда не ожидать появления 9-битных систем. Мой топ выбирает, почему:

  • Дополнительный бит данных получен от грабежа бит четности в основной памяти. Старое 8-битное ядро ​​содержало с ним скрытый бит четности. Каждый производитель сделал это. После того, как ядро ​​получило достаточно надежное решение, некоторые разработчики системы переключили уже существующую четность на бит данных в быстрой уловке, чтобы получить немного больше числовых адресов питания и памяти во время слабых, не MMU, машин. У текущей технологии памяти нет таких бит четности, машины не настолько слабы, а 64-разрядная память настолько велика. Все из которых должны сделать изменения дизайна менее рентабельными, тогда изменения были тогда.
  • Передача данных между 8-битной и 9-разрядной архитектурой, включая готовые локальные устройства ввода-вывода, а не только другие системы, была постоянной болью. Различные контроллеры в той же системе использовали несовместимые методы:
    • Используйте младшие 16-битные 18-битные слова.
    • Используйте младшие 8 бит 9-битных байтов, где дополнительный бит высокого порядка может быть установлен на четность из байтов, считанных с чувствительных к четности устройств.
    • Объедините младшие 6 бит из трех 8-битных байтов, чтобы сделать 18-битные двоичные слова.
    Некоторые контроллеры допускали выбор между 18-битной и 16-разрядной передачей данных во время выполнения. Какие будущие аппаратные средства и поддерживающие системные вызовы ваши программы будут находить просто не могут быть предсказаны заранее.
  • Подключение к 8-битовому Интернету будет достаточно ужасным, чтобы убить любые 9-битные мечты, которые у кого-то есть. Они ушли с ним тогда, когда машины были менее взаимосвязаны в те времена.
  • Наличие чего-то другого, кроме четного кратного 2 бита в памяти с байтовым адресом, вызывает всевозможные проблемы. Пример: если вам нужен массив из тысяч бит в 8-битных байтах, вы можете unsigned char bits[1024] = { 0 }; bits[n>>3] |= 1 << (n&7);. Чтобы полностью упаковать 9 бит, вы должны делать фактические деления, что приносит ужасные штрафные санкции. Это также относится к байтам за слово.
  • Любой код, на самом деле не протестированный на 9-разрядном байт-аппаратном обеспечении, может не справиться с этим первым реальным предприятием в стране неожиданных 9-битных байтов, если только код не является настолько простым, что рефакторинг в будущем для 9-бит второстепенная проблема. Для этого может помочь предыдущий метод byread()/bywrite(), но для установки режима передачи, вероятно, потребуется дополнительный режим CHAR_BIT, возвращающий, как текущий контроллер упорядочивает запрошенные байты.

Чтобы быть полным, любой, кто хочет беспокоиться о 9-битных байтах для образовательного опыта, может также беспокоиться о возврате одной системы дополнений; что-то еще, похоже, умерло заслуженной смертью (два нуля: +0 и -0, является источником продолжающихся кошмаров... поверьте мне). В то время 9-битные системы часто, казалось, были сопряжены с одной операцией дополнения.

Ответ 8

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

Вы сэкономите массу неприятностей, выполняя все вычисления в собственных типах данных и просто переписывая входы. Я представляю что-то вроде:

template<int OUTPUTBITS, typename CALLABLE>
class converter {
  converter(int inputbits, CALLABLE datasource);
  smallestTypeWithAtLeast<OUTPUTBITS> get();
};

Обратите внимание, что это может быть написано в будущем, когда такая машина существует, поэтому вам не нужно ничего делать сейчас. Или, если вы действительно параноик, убедитесь, что вы получаете только вызов источника данных, когда OUTPUTBUTS == inputbits.

Ответ 9

В языке программирования байт всегда 8 бит. Итак, если представление байта имеет 9 бит на какой-либо машине, по какой-то причине его до компилятора C согласовывает это. Пока вы пишете текст с помощью char, - скажем, если вы пишете/читаете "A" в файл, вы будете писать/читать только 8 бит в файл. Таким образом, у вас не должно быть никаких проблем.