|
Навигация
|
Главная » IBM Создание кода, независящего от порядка байтов, на языке C (исходники)Источник: IBM developerWorks Россия Харша С. Адига, инженер-программист, IBM ВведениеДля усвоения концепции порядка байтов, не обязательно разбираться в логических схемах организации памяти - нужно только понимать, что память представляет собой один большой массив. Массив содержит байты. Программисты используют адрес для указания на местоположение требуемого массива в памяти.
Хранение байтов в памятиМы будем оперировать 32-мя битами, т.е. четырьмя байтами. Целые числа или числа с плавающей точкой с обычной точностью записываются в 32 битах. Но поскольку каждый адрес в памяти может хранить только один байт, а не четыре, то 32-х битное число надо разбить на 4 байта. Например, предположим, что есть 32-х битное число, записанное как 12345678, которое является шестнадцатеричным. Поскольку каждая шестнадцатеричная цифра представляется четырьмя байтами, то необходимо восемь шестнадцатеричных чисел для представления рассматриваемого 32-х битного значения. Четыре байта это: 12, 34, 56, и 78. Есть два способа хранить это в памяти, как показано ниже.
Регистры и порядок байтовПорядок байтов имеет значения только тогда, когда нужно разбить многобайтовую последовательность и записать полученные байты в последовательные участки памяти. Однако если имеется 32-х битный регистр, хранящий 32-х битное значение, то нет смысла говорить о порядке размещения байтов в памяти. Регистр не чувствителен к порядку "от старшего к младшему" или "от младшего к старшему"; регистр только хранит 32-х битное значение. Крайне правый бит является младшим, крайне левый бит является старшим.Некоторые люди считают, что регистр имеет порядок "от старшего к младшему", потому что он записывает старшие байты в младшие адреса памяти. Важность порядка байтовПорядок байтов является атрибутом системы, который определяет, представляются ли целые числа слева-направо или справа-налево. В сегодняшнем мире виртуальных машин и гигагерцевых процессоров многие программисты задумываются, почему они должны учитывать вопрос, рассматриваемый в этой статье? К сожалению, необходимо учитывать порядок байтов каждый раз при разработке аппаратного или программного обеспечения. И, в общем-то, нет универсального правила о том, какой порядок байтов использовать.Все процессоры должны быть разработаны с учетом либо порядка "от младшего к старшему" или "от старшего к младшему". Например, процессоры Intel® семейства 80x86 и их клоны используют "от младшего к старшему", в то время как процессоры Sun SPARC, Motorola 68K, и PowerPC® используют порядок "от старшего к младшему". Почему порядок байт так важен? Представьте, что нужно записывать целочисленные значения в файл, и послать этот файл компьютеру, который использует противоположный порядок чтения байтов; этот компьютер прочтет записанное вам в файл значение неверно. Это происходит из-за разных порядков размещения байтов в памяти; в этом случае надо читать значение задом наперед для его корректности. Порядок записи байт в память представляет собой большую проблему при пересылке через сеть. Еще раз повторю, что если послать число, созданное в одном порядке записи байтов, на компьютер, использующий противоположный порядок записи, то возникнет проблема. Ситуация усложняется еще больше, если неизвестен порядок записи байтов на удаленной машине. Пример 1 показывает, к чему приводит программирование без учета различий в направлении записи байтов. Пример 1. Программирование без учета различий в направлении записи байтов
Приведенный выше код корректно скомпилируется на любом компьютере. Однако выводимый результат будет разным из-за различных порядков записи байтов в память. Вывод программы после просмотра его утилитой hexdump , будет таким, как в примерах 2 и 3.Пример 2. Вывод команды hexdump -C на компьютере с порядком "от старшего к меньшему"
Пример 3. Вывод команды hexdump -C с порядком записи "от младшего к старшему"
Влияние порядка хранения байт в памяти на программный кодРазличие в порядке байтов далеко не всегда влияет на результат операций. Если выполняются побитовые операции или операции побитового сдвига на целочисленных значениях, то не надо учитывать порядок байтов в памяти. Компьютер упорядочивает многочисленные байты таким образом, что младший байт всегда остается самым младшим, старший байт всегда является старшим.Естественно в таком случае задаться вопросом, могут ли строки сохраняться в каком-либо необычном порядке, характером для конкретного компьютера. Для ответа на этот вопрос, вернемся к основам организации массивов. Строка в языке C представляет собой массив символов. Каждый символ требует одного байта памяти, при условии, что символы отображаются в кодировке ASCII. В массиве адрес последовательных элементов возрастает. Таким образом, адрес &arr[i] меньше чем адрес &arr[i+1]. Хотя это и не является очевидным, если что-либо хранится в ячейках памяти, адреса которых последовательно увеличиваются, оно будет записано в файл в такой же возрастающей последовательности. При записи в файл обычно задается адрес в памяти и число байтов, которое нужно записать в файл, начиная с этого адреса. Предположим, есть строка man . Будем считать, что m хранится по адресу 1000, a по адресу 1001, и n по адресу 1002. Символ конца строки \0 хранится по адресу 1003. Следуя из того, что строки в С являются массивами символов, к ним применяются правила работы с символами. В отличие от типов int или long, можно легко различать отдельные байты в строке. Индексация массивов используется для обеспечения доступа к байтам (символам) строки, нельзя просто обращаться к отдельным байтам типов int или long - для этого надо использовать указатели. Отдельные байты в int или long в большей или меньшей степени скрыты от программиста.Теперь представим, что эту строку нужно записывать в файл при помощи метода типа write() . Ставим указатель на m и задаем число байтов, которое нужно записать в файл (в данном случае четыре). Метод write() обрабатывает байт за байтом и записывает их в файл начиная с m и заканчивая символом конца строки.Итак, мы доказали, что порядок байтов не влияет на представление строк в языке С. Порядок байтов имеет значение , когда вы используете приведение типов, которое зависит от конкретного порядка байтов. Пример такой ситуации показан в примере 4, но учтите, что существует много различных приведений типов, которые могут вызвать проблемы. Пример 4. Принудительное задание порядка байтов
Каким будет значение x ? Давайте взглянем, что делает этот код. Мы создали двухбайтный массив, а затем преобразовали его к типу short. Используя массив, мы фактически принуждаем систему к использованию какого-либо конкретного порядка байтов; давайте посмотрим, как система обработает эти два байта.В случае, если используется подход "от младшего к старшему", 0 и 1 интерпретируются задом наперед и будут представлены как 0,1. Так как старший байт 0, а младший байт 1, значение x будет равным 1.С другой стороны, в системе с порядком "от старшего к младшему" старшим байтом будет 1 и значение переменной x будет равным 256.Определения порядка байтов во время выполнения программы Один из способов определить порядок байтов в системе - это проверить расположение в памяти предопределенной константы. Напомним, что размещение единицы (1) типа целочисленного 32-х битного числа будет следующим - 00 00 00 01 для порядка "от старшего к младшему" и 01 00 00 00 для порядка "от младшего к старшему". Взглянув на первый байт этой константы, можно указать порядок байтов у конкретной платформы, и затем предпринять наиболее эффективное в данной ситуации действие. Пример 5 проверяет первый байт целого числа i для того, чтобы определить, является оно 0 или 1. Если оно равно 1, текущая платформа использует режим байтов в памяти "от младшего к старшему", а если 0 - то режим "от старшего к младшему".Пример 5. Определение порядка байтов
Другой способ определить порядок байтов состоит в использовании символьных указателей на байты в числе типа int и затем проверить первый байт - является он 0 или 1. Пример 6 иллюстрирует этот способ. Пример 6. Символьные указатели
Сетевой порядок байтовСетевые стеки и протоколы также должны определять свою последовательность байтов, иначе два узла сети с разным порядком байтов просто не смогут взаимодействовать. Это наиболее яркий пример влияния порядка байтов на программы. Все уровни протокола TCP/IP работают в режиме "от старшего к младшему". Любое 16-ти или 32-х битное значение внутри заголовков различных уровней (такое как IP-адрес, длина пакета, контрольная сумма) должны отсылаться и получаться так, чтобы старший байт был первым.Порядок байтов "от старшего к младшему", используемый в протоколе TCP/IP, иногда еще называют сетевым порядком байтов . Даже если компьютеры в сети используют порядок "от младшего к старшему", многобайтные целочисленные значения для передачи их по сети должны быть преобразованы в сетевой порядок байтов, а затем еще раз преобразованы назад в порядок "от младшего к старшему" на принимающем компьютере. Предположим, что нужно установить TCP-соединение с компьютером, чей IP-адрес равен 192.0.1.2. IPv4 использует уникальное 32-х битное целое число для идентификации каждого компьютера в сети. Разделенный точками IP-адрес должен быть представлен в качестве целочисленного значения. Например, ПК на базе 80x86 связывается с сервером на базе SPARC через Интернет. Без каких-либо дополнительных действий со стороны пользователя процессор 80x86 может преобразовать 192.0.1.2 в целочисленное число с последовательностью байтов "от младшего к старшему", равное 0x020100C0, и передать байты в последовательности 02 01 00 C0. SPARC получит байты в порядке 02 01 00 C0, переведет байты в порядок "от старшего к младшему" 0x020100c0, и неправильно прочтет IP-адрес 2.1.0.192. Если стек работает на процессоре, использующем порядок байтов "от младшего к старшему", он должен переупорядочить во время выполнения байты каждого многобайтного значения из заголовков уровней протокола TCP/IP. Если стек работает в режиме байтов "от большего к меньшему", то нет повода для беспокойств. Чтобы стек обладал переносимостью (работал на процессоре обоих типов), он должен уметь принимать решение о необходимости совершения переупорядочивания байтов во время компиляции. Для осуществления подобного переупорядочивания сокеты предоставляют набор макросов для конвертирования байтов согласно последовательности хранения их на хосте и конвертированию байтов, при передачи их с хоста, в сетевой порядок байтов, как показано ниже.
Пример 7. Программа на языке С
Эта программа показывает, как хранится переменная x типа long, хранящее значение 112A380 (шестнадцатеричное). Когда эта программа выполняется на процессоре, использующем порядок байтов "от младшего к старшему", она выводит информацию как в примере 8. Пример 8. Результат работы программы на процессоре с режимом "от младшего к старшему"
Если посмотреть на отдельные байты x , то видно, что младший байт (0x80) находится по меньшему адресу. После этого вызвать htonl( ) для конвертирования в сетевой порядок байтов, то в результате старший байт (0x1) окажется по меньшему адресу. Естественно, что если распечатать значение переменной x после изменения ее порядка байтов, то получится бессмысленное число.Пример 9 показывает результаты работы той же программы на процессоре с режимом "от старшего к младшему". Пример 9. Результат работы программы на процессоре с режимом "от старшего к младшему"
Здесь видно, что самый старший байт (0x1) записан под меньшим адресом. Вызов htonl() для конвертирования в сетевой порядок не изменит ничего потому, что порядок байтов "от старшего к младшему".Изменение на обратный порядка байтовТеперь напишем программу, результаты работы которой не зависят от порядка байтов. Необходимо убедиться, что данные в файле записаны в верном порядке при записи в этот файл или чтении из него данных. Также следует избегать использования флагов условной компиляции и предусмотреть в коде программы возможностью автоматического определения порядок байтов, используемый на конкретном компьютере.Создадим набор функций, которые автоматически меняет на обратный порядок байтов заданного параметра в зависимости от порядка байтов на компьютере. Сначала нужно разобраться с параметром s типа short , разделив его два байта, а затем "склеить" их в обратном порядке. Как показано в примере 10 ниже, функция вернет реверсированное значение переменной типа short в случае, если процессор использует порядок байтов "от младшего к старшему". В противном случае функция оставит прежним значение переменной s .Пример 10. Метод 1: Использование побитового сдвига и склеивания битов
В функции ниже преобразуется переменнаяю типа short , чтобы представить ее как массив символов, а затем создается новый массив, являющийся обратным первому в случае, если процессор использует режим "от младшего к старшему".Пример 11. Метод 2: Использование указателей на символьный массив
Теперь перейдем к типу int .Пример 12. Метод 1: Использование побитового сдвига и склеивания байтов для типа int
Это в большей или меньшей степени соответствует тому, что мы раньше делали для изменения на обратный порядка для типа short , но для четырех байтов, а не двух.Пример 13. Метод 2: Использование указателей на символьный массив для типа int
То же самое мы делали для реверсирования переменной типа short , но здесь обрабатывались четыре байта.Точно также можно менять на обратный порядок байтов для типов float, long, double и других типов, но рассмотрение этих вопросов выходит за рамки данной статьи. ЗаключениеПо большому счету, нет особого преимущества в использовании того или иного порядка байтов. Оба порядка распространены и используются в архитектуре многих ЭВМ. Процессоры, работающие в режиме "от младшего к старшему" используются на большинстве персональных компьютеров.Проблемы с порядком байтов не затрагивают переменные, что хранятся только в одном байте, поскольку "байт" считается элементарной единицей хранения информации в памяти. С другой стороны многобайтные переменные зависят от порядка байтов , что следует иметь в виду при создании приложения. Создание кода, независящего от порядка байтов, на языке C (исходники). IBM остается мировым лидером в сегменте управления предприятием. Telelogic поможет оптимизировать процесс разработки. Приглашаем на cеминар по продуктам компании IBM Rational. IBM представила новые "облачные" сервисы для коллективной работы. Главная » IBM |
© 2024 Team.Furia.Ru.
Частичное копирование материалов разрешено. |