Размер байта

Последний раз обновлено 10.02.014


Мне довольно трудно отойти от вступления и перейти к делу. Наверное продолжение я буду писать уже завтра. Как видите, написание текстов имеет свои тонкости, может быть вступления надо добавлять в конце работы над текстом.

Написание стандартов тоже имеет свои тонкости, о которых нам неизвестно, но слушая обычных сторонников стандартов языка С и С++, можно догадаться, что они верят, что стандарт на эти языки сделает программы не только компилируемыми, но и совместимыми с разными реальными системами. Это заблуждение происходит оттого, что такие сторонники часто не учитывают или даже не знают о "rationale", лежащем за тем или иным требованием стандарта.

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

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

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

Давайте рассмотрим целые типы языка (POD): char, int и модификаторы short, long, unsigned. Типы выглядят красиво, не зависят от разрядности машины и программа их использующая, казалось бы, могла бы быть портируемой.

Но на деле они порождают неимоверное количество проблем, запечатленных в истории. Встретить эти проблемы можно в обработке текстовых файлов с буквой "я" на процессоре i286, в секции BIOS для обслуживания жесткого диска на процессоре i586 и в бесчисленном количестве приложений для всех типов процессоров, где переполнение или знак используются неправильно во время выполнения.

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

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

Как же тогда быть с портируемостью? Например, мы задаем int64 и пытаемся исполнить нашу программу на 16 битном окружении. Ведь не будет работать. Конечно же не будет, только с именем "int64" вы это увидите уже во время программирования, а с именем "int" только во время выполнения.

Значит написать портируемую программу нельзя? Программу, которой нужен непрерывный массив размером 24бит эффективно исполнить на компьютере с общей памятью размером 16бит нельзя. Наоборот можно.

Для работы с переменными С памяти auto, программист вынужден заранее выбирать разрядность переменной, исходя из требований алгоритма работы. Значит суффикс может быть любым? Может, но лучше учесть и соображения эффективности.

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

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

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

В языке С память это множество бит. В языке С есть зарезервированное слово "char". С одной стороны тип "char" это вариант int, который служит для хранения кодов символов; с другой стороны понятие "char" служит для обозначение особой группы из нескольких бит, такой группы, что:

Требование минимума в 8 бит вероятно историческое, связанное с ASCII кодами и стандартной библиотекой С. В чем то char оказался даже основательней int, поскольку int можно было бы задать как typedef для long модификации типа char.

Сразу прокомментируем системы, для которых 8 бит это много. Для таких систем размеры кода и данных как правило тоже очень малы (это может быть пара килобайт или даже сотня байт), о портировании кода между системами здесь не приходится говорить. Усилия по написанию нового кода будут соизмеримы с усилиями по портированию старого, поэтому для таких небольших систем абстрактная машина С несовместима с современными многоядерными ПК. Если же совместимость все равно нужна, то 8 бит надо будет эмулировать.

На процессорах х86 "char" это будет "байт", а "байт" это историческая разрядность ALU и шины данных первых процессоров данной серии, так что система команд процессора позволяет в пределах системы команд предшествующего процессора эффективно работать с такой разрядностью (реальная разрядность ALU называется "машинным словом").

На процессорах х86 "байт" равен 8 битам. Также "байт" равный 8 битам используется повсеместно (для измерения количества памяти оперативной, кэша, диска), как внесистемная единица.

Ясно, что на процессорах х86 следует применять суффиксы 8,16,32,64. Они не потребуют эмуляции. Сомнения многих сразу вызовет суффикс 16. Я думаю, что если есть возможность использовать 16 бит данные, их надо использовать. Портируемая программа, не затребовавшая без нужды 32 битые данные, сможет работать в 16 битном окружении другого процессора более эффективно.

Проблемой являются процессоры, для которых char состоит из 9,12 и т.п. количества бит. Повторим, что в этом случае с эффективностью ничего нельзя поделать, алгоритм не может быть рассчитан на неопределенный размер регистра. Если ваша программа оригинально рассчитана на 16 битный аппаратный регистр, то при ее портировании на 18 битный аппаратный регистр потребуется эмуляция операций классом С++ или компилятором.

Чтобы понять как делать эмуляцию нестандартной разрядности, надо понять какие POD типы нам на деле нужны. А нужно их нам несколько и не всегда будут нужны именно регистры с их аппаратными особенностями арифметики.


Содержание