Что такое младший бит и старший бит

Побитовые или поразрядные операции

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

Кроме того, рассматриваются операции сдвигов «, ».

Значение старшего, младшего слова(2 байта), бита

Запись многобайтового числа из памяти компьютера в файл или передача по сети требует соблюдения соглашений о том, какой из байтов является старшим, а какой младшим. Прямая запись ячеек памяти приводит к возможным проблемам при переносе приложения с платформы на платформу. Варианты записи: от старшего к младшему или (англ. big-endian, дословно: «тупоконечный»): этот порядок является стандартным для протоколов TCP/IP, он используется в заголовках пакетов данных и во многих протоколах более высокого уровня, разработанных для использования поверх TCP/IP. Поэтому, порядок байтов от старшего к младшему часто называют сетевым порядком байтов (англ. network byte order). От младшего к старшему или (англ. little-endian, дословно: «остроконечный»): запись начинается с младшего и заканчивается старшим. Этот порядок записи принят в памяти персональных компьютеров с x86-процессорами, в связи с чем иногда его называют интеловский порядок байтов.

Чтобы получить значение младщего слова (OWORD)

Операции

потому что только нулевой и четвертый разряды обоих операндов содержат 1.

потому что все разряды (кроме шестого) в одном из двух операндов имеют значение 1.

Заметим, что, поскольку нулевой разряд в обоих операндах имеет значение 1, нулевой разряд результата имеет значение 0.

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

Таким образом, х«2 сдвигает х влево на 2 позиции, заполняя освобождающиеся позиции нулями (эквивалентно умножению на 4).

Для значений без знака имеем

Эти две операции выполняют сдвиг, а также эффективное умножение и деление на степени числа 2.

Комментарии к коду.

Побитовые операторы JavaScript

Для понимания побитовых операторов необходимо свободно уметь работать с двоичным представлением чисел. Если это не так, остается только надеяться, что данные операторы не часто вам будут попадаться в вашей практике. Ниже следует перечень побитовых операторов с примерами их применения (примеры и результаты даны, так же, и в бинарной (двоичной) форме):

Таблица. Побитовые операторы.

Листинг: определение четности числа

Если в результате получится значение false, то заданное число является нечетным, в противном случае, число является четным.

Источник

Понятие порядка байтов в цифровых системах: прямой (Big Endian) и обратный (Little Endian) порядок байтов

Различные термины «порядка байтов» («endian») могут показаться немного странными, но основная концепция довольно проста. Если вы еще не хорошо знакомы с вариантами порядка байтов, читайте статью дальше!

Порядок байтов, прямой порядок (big endian), обратный порядок (little endian). Что означают эти термины, и как они влияют на работу инженеров?

Что такое порядок байтов?

Оказывает, это неправильный вопрос. При обсуждении данных «порядок байтов» не является отдельным термином. Вернее, к форматам расположения байтов относятся термины «прямой порядок» («big-endian») и «обратный порядок» («little-endian»).

Термины берут начало в «Путешествиях Гулливера» Джонатана Свифта, в которых начинается гражданская война между теми, кто предпочитает разбивать вареные яйца на большом конце («big-endians»), и теми, кто предпочитает разбивать их на маленьком конце («little-endians»).

В 1980 году израильский ученый-компьютерщик Денни Коэн написал статью («О священных войнах и призыве к миру»), в которой он представил насмешливое объяснение столь же мелкой «войны», вызванной одним вопросом:

«Каков правильный порядок байтов в сообщениях?»

Чтобы объяснить эту проблему, он позаимствовал у Свифта термины «big endian» и «little endian», чтобы описать две противоположные стороны дискуссии о том, что он называл «endianness» (в данном контексте «порядок байтов»).

Когда Свифт писал «Путешествия Гулливера» где-то в первой четверти восемнадцатого века, он, конечно, не знал, что однажды его работа послужит вдохновением для неологизмов двадцатого века, которые определяют расположение цифровых данных в памяти и системах связи. Но такова жизнь – часто странная и всегда непредсказуемая.

Зачем нам нужен порядок байтов

Несмотря на сатирическую трактовку Коэном борьбы «big endians» (прямого порядка, от старшего к младшему) против «little endians» (обратного порядка, от младшего к старшему), вопрос о порядке байтов на самом деле очень важен для нашей работы с данными.

Блок цифровой информации – это последовательность единиц и нулей. Эти единицы и нули начинаются с наименьшего значащего бита (least significant bit, LSb – обратите на строчную букву «b») и заканчиваются на наибольшем значащем бите (most significant bit, MSb).

Это кажется достаточно простым; рассмотрим следующий гипотетический сценарий.

32-разрядный процессор готов к сохранению данных и, следовательно, передает 32 бита данных в соответствующие 32 блока памяти. Этим 32 блокам памяти совместно назначается адрес, скажем 0x01. Шина данных в системе спроектирована таким образом, что нет возможности смешивать LSb с MSb, и все операции используют 32-битные данные, даже если соответствующие числа могут быть легко представлены в 16 или даже 8 битами. Когда процессору требуется получить доступ к сохраненным данным, он просто считывает 32 бита с адреса памяти 0x01. Эта система является надежной, и нет необходимости вводить понятие порядка байтов.

Возможно, вы заметили, что слово «байт» в описании этого гипотетического процессора нигде не упоминалось. Всё основано на 32-битных данных – зачем нужно делить эти данные на 8-битные части, если всё оборудование предназначено для обработки 32-битных данных? Вот здесь-то теория и реальность расходятся. Реальные цифровые системы, даже те, которые могут напрямую обрабатывать 32-битные или 64-битные данные, широко использую 8-битный сегмент данных, известный как байт.

Порядок байтов в памяти

Удобным средством демонстрации порядка байтов действии и объяснения разницы между прямым и обратным порядками является процесс хранения цифровых данных. Представьте, что мы используем 8-разрядный микроконтроллер. Всё аппаратное обеспечение в этом устройстве, включая ячейки памяти, предназначено для 8-битных данных. Таким образом, адрес 0x00 может хранить один байт, адрес 0x01 тоже хранит один байт, и так далее.

Что такое младший бит и старший бит. Смотреть фото Что такое младший бит и старший бит. Смотреть картинку Что такое младший бит и старший бит. Картинка про Что такое младший бит и старший бит. Фото Что такое младший бит и старший бит Эта схема показывает 11 байтов памяти, то есть 11 ячеек памяти, причем каждая ячейка хранит 8 бит данных

Допустим, мы решили запрограммировать этот микроконтроллер, используя компилятор C, который позволяет нам определять 32-разрядные (т.е. 4-байтовые) переменные. Компилятор должен хранить эти переменные в смежных ячейках памяти, но что не очень понятно, так это то, в самом младшем адресе памяти должен храниться наибольший значащий байт (most significant byte, MSB – обратите внимание на заглавную «B») или наименьший значащий байт (least significant byte, LSB).

Другими словами, должна ли система использовать порядок памяти от старшего к младшему (прямой порядок, big-endian) или от младшего к старшему (обратный порядок, little-endian)?

Что такое младший бит и старший бит. Смотреть фото Что такое младший бит и старший бит. Смотреть картинку Что такое младший бит и старший бит. Картинка про Что такое младший бит и старший бит. Фото Что такое младший бит и старший бит Хранение данных с прямым порядком и с обратным порядком. » D » относится к 32-разрядному слову данных, а номера индексов указывают на отдельные биты от MSb ( D31 ) до LSb ( D0 )

Здесь на самом деле нет правильного или неправильного ответа – любая договоренность может быть совершенно эффективной. Решение между прямым и обратным порядком может быть основано, например, на поддержании совместимости с предыдущими версиями данного процессора, что, конечно, поднимает вопрос о том, как инженеры приняли решение для первого процессора в этом семействе. Я не знаю; возможно, генеральный директор подбросил монету.

Прямой порядок против обратного порядка

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

Обратный порядок (little endian) указывает на организацию, которая начинается с «маленького» конца и продолжается в направлении «большого» конца.

Решение между прямым и обратным порядками байтов не ограничивается схемами памяти и 8-разрядными процессорами. Байт является универсальной единицей в цифровых системах. Подумайте только о персональных компьютерах: пространство на жестком диске измеряется в байтах, ОЗУ измеряется в байтах, скорость передачи данных по USB указывается в байтах в секунду (или в битах в секунду), и это несмотря на тот факт, что 8-разрядные персональные компьютеры полностью устарели. Вопрос о порядке байтов вступает в игру всякий раз, когда цифровая система совмещает хранение или передачу данных на основе байтов с числовыми значениями, длина которых превышает 8 бит.

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

Что такое младший бит и старший бит. Смотреть фото Что такое младший бит и старший бит. Смотреть картинку Что такое младший бит и старший бит. Картинка про Что такое младший бит и старший бит. Фото Что такое младший бит и старший бит Порядок байтов в контексте последовательной передачи данных

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

Примером интерпретации на основе порядка байтов является случай, когда байты данных передаются от модуля датчика на ПК через «последовательный порт» (что в настоящее время почти наверняка означает, что в качестве COM порта используется USB соединение). Допустим, всё, что вам нужно сделать, это вывести эти данные, используя какой-то код MATLAB. Когда вы вводите эти байты в среду MATLAB и конвертируете их в обычные переменные, вы должны интерпретировать значения отдельных байтов в соответствии с порядком, в котором они хранятся в памяти.

Заключение

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

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

Источник

Русские Блоги

О сетевом порядке байтов

Исходный адрес:https://blog.csdn.net/erlib/article/details/8937068
В последние несколько дней я снова начал создавать сетевые приложения. Так как это сетевое программирование, порядок байтов должен быть важным элементом знаний, о котором следует помнить. Разместите статью как напоминание!

Различные процессоры имеют разные типы байтов. Эти порядки байтов относятся к порядку, в котором целые числа хранятся в памяти. Это называется порядком узлов.
Есть два наиболее распространенных
1. Little endian: храните младший байт в начальном адресе
2. Big endian: хранить старший байт в начальном адресе

LE little-endian
BE big-endian

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

Для преобразования сокет bsd предоставляет следующие четыре функции преобразования:

В системах с прямым порядком байтов эти функции преобразуют порядок байтов.
В системах с прямым порядком байтов эти функции будут определены как пустые макросы.

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

Заметка:

Один, определение порядка байтов

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

Во всех статьях о порядке байтов будет упоминаться, что порядок байтов делится на две категории: Big-Endian и Little-Endian. Определения Big-Endian и Little-Endian, которые цитируют стандарт, следующие:
a) Little-Endian означает, что младший байт помещается в конец младшего адреса памяти, а старший байт помещается в конец старшего адреса памяти.
б) Big-Endian означает, что старший байт помещается в конец младшего адреса памяти, а младший байт помещается в конец высокого адреса памяти.
c) Сетевой порядок байтов: 4 байта 32-битных значений передаются в следующем порядке: сначала 0 ~ 7 бит, затем 8 ~ 15 бит, затем 16 ~ 23 бит и, наконец, 24

2. Старший / младший адрес, старший и младший байты

Прежде всего, нам нужно знать структуру пространства памяти в нашем образе программы C: есть инструкции по структуре пространства памяти в «C Expert Programming» или «Unix Environment Advanced Programming», примерно следующим образом:

И старший и младший адреса, и старший и младший байты очищены. Давайте еще раз рассмотрим определение обратного порядка байтов и обратного порядка байтов и проиллюстрируем два порядка байтов с помощью значков:
В качестве примера возьмем значение unsigned int = 0x12345678 и рассмотрим условия хранения в двух степенях порядка байтов соответственно. Мы можем использовать unsigned char buf [4] для представления значения:
Big-Endian: младший адрес хранит старший бит, как показано ниже:

Intel X86 использует Little-Endian на существующих платформах, а SPARC, как Sun, использует Big-Endian.

Три, примеры

Разработчики встроенных систем должны хорошо разбираться в режимах Little-endian и Big-endian. ЦП, использующий режим обратного порядка байтов, сохраняет операнды от младшего байта к старшему, а режим прямого порядка байтов сохраняет операнды от старшего байта к младшему.

Источник

Что такое младший бит и старший бит

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

1.1 Двоичные числа

Чтобы сделать вычислительные системы более надежными и простыми, их аппаратура строится из простейших электронных схем, которые могут находиться только в двух состояниях. Одно из них обозначается 0, а другое – 1. Такая схема предназначена для длительного или краткого хранения самой мелкой единицы информации – бита (от «BInary digiT» – двоичная цифра).

Любое число можно представить в виде цепочки битов. Такое представление числа называется двоичным числом. Цепочка из восьми битов называется байтом (рис. 1).

Что такое младший бит и старший бит. Смотреть фото Что такое младший бит и старший бит. Смотреть картинку Что такое младший бит и старший бит. Картинка про Что такое младший бит и старший бит. Фото Что такое младший бит и старший бит Что такое младший бит и старший бит. Смотреть фото Что такое младший бит и старший бит. Смотреть картинку Что такое младший бит и старший бит. Картинка про Что такое младший бит и старший бит. Фото Что такое младший бит и старший бит

старший бит (бит 7) младший бит (бит 0)

Рис. 1. Пример байта

Величина двоичного числа определяется относительной позицией каждого бита и его значением. Позиционный вес младшего бита 2 о = 1(10), где 1(10) – единица в десятичной системе счисления. Следующий бит имеет вес 2 1 = 2(10). Вес любой позиции получается удвоением веса предыдущей позиции (рис. 2).

Что такое младший бит и старший бит. Смотреть фото Что такое младший бит и старший бит. Смотреть картинку Что такое младший бит и старший бит. Картинка про Что такое младший бит и старший бит. Фото Что такое младший бит и старший бит

Рис. 2. Веса позиций байта

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

Что такое младший бит и старший бит. Смотреть фото Что такое младший бит и старший бит. Смотреть картинку Что такое младший бит и старший бит. Картинка про Что такое младший бит и старший бит. Фото Что такое младший бит и старший бит

Записывая 0 в остальные позиции битов (биты 0,2,3) получаем окончательный результат: 110010.

Для выполнения обратного преобразования следует сложить десятичные веса тех позиций, в которых стоит 1:

32 (бит 5) + 16 (бит 4) + 2 (бит 1) = 50

Байт может представлять десятичные положительные числа от 0 (00000000) до 255 (11111111). Число 255 может быть получено двумя способами: 1) суммированием весов всех битов байта; 2) по формуле 2 8 – 1, где 8 – номер первого бита, не вошедшего в состав байта.

Машинным словом будем называть битовую строку длиной 16 битов. Одно слово содержит 2 байта (рис. 3). Каждый бит слова имеет свой вес. Просуммировав все веса, найдем максимальное целое число без знака, которое можно записать в одно слово, оно равно 2 16 – 1 = 65535.

Двоичное содержимое байта или слова может рассматриваться (интерпретироваться) как число без знака и как число со знаком. Число без знака занимает все 16 битов слова или 8 битов байта. Оно может быть только положительным. Просуммируем два таких числа:

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

Что такое младший бит и старший бит. Смотреть фото Что такое младший бит и старший бит. Смотреть картинку Что такое младший бит и старший бит. Картинка про Что такое младший бит и старший бит. Фото Что такое младший бит и старший бит

Рис. 3. Веса позиций слова

все биты числа (в том числе и знаковый) инвертируются;

к полученному числу прибавляется 1.

Например, получим дополнительный код числа –65:

Для получения абсолютного значения отрицательного числа повторяют эти же самые два действия. Например:

Сумма +65 и –65 должна составить ноль:

В данном примере у нас произошли два интересных переноса: 1) в знаковый (7-й) разряд; 2) за пределы байта. Первая единица переноса обрабатывается как обычно, а вторая теряется. Оба переноса считаются правильными.

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

Источник

Разбираемся с прямым и обратным порядком байтов

Числа и данные

Наиболее важная концепция заключается в понимании разницы между числами и данными, которые эти числа представляют. Число — это абстрактное понятия, как исчислитель чего-то. У Вас есть десять пальцев. Понятие “десять” не меняется, в зависимости от использованного представления: десять, 10, diez (испанский), ju (японский), 1010 (бинарное представление), Х (римские числа)… Все эти представления указывают на понятие “десяти”.

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

Данные — это как человеческое письмо, просто набор отметок на бумаге. Этим отметкам не присуще какое-либо значение. Если мы видим линию и круг (например, |O), то можно интерпретировать это как “десять”. Но это лишь предположение, что считанные символы представляют число. Это могут быть буквы “IO” — название спутника Юпитера. Или, возможно, имя греческой богини. Или аббревиатура для ввода/вывода. Или чьи-то инициалы. Или число 2 в бинарном представлении (“10”). Этот список предположений можно продолжить. Дело в том, что один фрагмент данных (|O) может быть интерпретировано по разному, и смысл остается не ясен, пока кто-то не уточнит намерения автора.

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

Почему так происходит? Ну, вообще-то нет такого правила, что компьютеры должны использовать один и тот же язык, так же, как нет такого правила и для людей. Каждый компьютер одного типа имеет внутреннюю совместимость (он может считывать свои собственные данные), но нет никакой гарантии, как именно интерпретирует эти данные компьютер другого типа.

Храним числа как данные

Так в чем же проблема — компьютеры отлично ладят с одиночными байтами, правда? Ну, все превосходно для однобайтных данных, таких как ASCII-символы. Однако, много данных используют для хранения несколько байтов, например, целые числа или числа с плавающей точкой. И нет никакого соглашения о том, в каком порядке должны хранится эти последовательности.

Пример с байтом

Рассмотрим последовательность из 4 байт. Назовем их W X Y и Z. Я избегаю наименований A B C D, потому что это шестнадцатеричные числа, что может немного запутывать. Итак, каждый байт имеет значение и состоит из 8 бит.

Например, W — это один байт со значением 0х12 в шестнадцатеричном виде или 00010010 в бинарном. Если W будет интерпретироваться как число, то это будет “18” в десятеричной системе (между прочим, ничто не указывает на то, что мы должны интерпретировать этот байт как число — это может быть ASCII-символ или что-то совсем иное). Вы все еще со мной? Мы имеем 4 байта, W X Y и Z, каждый с различным значением.

Понимаем указатели

Указатели являются ключевой частью программирования, особенно в языке С. Указатель представляет собой число, являющееся адресом в памяти. И это зависит только от нас (программистов), как интерпретировать данные по этому адресу.

В языке С, когда вы кастите (приводите) указатель к конкретному типу (такому как char * или int *), это говорит компьютеру, как именно интерпретировать данные по этому адресу. Например, давайте объявим:

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

Теперь предположим, что мы напишем:

Этот оператор говорит компьютеру, что р указывает на то же место, и данные по этому адресу нужно интерпретировать как один символ (1 байт). В этом случае, с будет указывать на память по адресу 0, или на байт W. Если мы выведем с, то получим значение, хранящееся в W, которое равно шестнадцатеричному 0x12 (помните, что W — это полный байт). Этот пример не зависит от типа компьютера — опять же, все компьютеры одинаково хорошо понимают, что же такое один байт (в прошлом это было не всегда так).

Этот пример полезен, он одинаково работает на все компьютерах — если у нас есть указатель на байт (char *, один байт), мы можем проходить по памяти, считывая по одному байту за раз. Мы можем обратиться к любому месту в памяти, и порядок хранения байт не будет иметь никакого значения — любой компьютер вернет нам одинаковую информацию.

Так в чем же проблема?

Проблемы начинаются, когда компьютер пытается считать несколько байт. Многие типы данных состоят больше чем из одного байта, например, длинные целые (long integers) или числа с плавающей точкой. Байт имеет только 256 значений и может хранить числа от 0 до 255.

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

Теперь предположим, что у нас есть 4 байта (WXYZ), которые хранятся одинаково на машинах с обоими типами порядка записи байтов. То есть, ячейка памяти 0 соответствует W, ячейка 1 соответствует X и т. д.

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

Такой код будет работать на любой машине и успешно установит значение байт W, X, Y и Z расположенных на соответствующих позициях 0, 1, 2 и 3.

Интерпретация данных

Теперь давайте рассмотрим пример с многобайтными данными (наконец-то!). Короткая сводка: “short int” это 2-х байтовое число (16 бит), которое может иметь значение от 0 до 65535 (если оно беззнаковое). Давайте используем его в примере.

Теперь Вы видите проблему? Машина с порядком хранения от старшего к младшему считает, что s = 0x1234, в то время как машина с порядком хранения от младшего к старшему думает, что s = 0x3412. Абсолютно одинаковые данные дают в результате два совершенно разных числа.

И еще один пример

Давайте для “веселья” рассмотрим еще один пример с 4 байтовым целым:

Проблема NUXI

Проблему с порядком байт иногда называют проблемой NUXI: слово UNIX, сохраненное на машинах с порядком хранения от старшего к младшему, будет отображаться как NUXI на машинах с порядком от младшего к старшему.

Допустим, что мы собираемся сохранить 4 байта (U, N, I, и X), как два short int: UN и IX. Каждая буква занимает целый байт, как в случае с WXYZ. Для сохранения двух значений типа short int напишем следующий код:

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

Однако, если пройтись по памяти по одному байту за раз (используя трюк с char *), то порядок байт может различаться. На машине с прямым порядком хранения мы увидим:

Что имеет смысл. “U” является старшим байтом в “UN” и соответственно хранится первым. Такая же ситуация для “IX”, где “I” — это старший байт и хранится он первым.

На машине с обратным порядком хранения мы скорее всего увидим:

Но и это тоже имеет смысл. “N” является младшим байтом в “UN” и значит хранится он первым. Опять же, хотя байты хранятся в “обратном порядке” в памяти, машины с порядком хранения от младшего к старшему знают что это обратный порядок байт, и интерпретирует их правильно при чтении. Также, обратите внимание, что мы можем определять шестнадцатеричные числа, такие как 0x1234, на любой машине. Машина с обратным порядком хранения байтов знает, что Вы имеете в виду, когда пишите 0x1234 и не заставит Вас менять значения местами (когда шестнадцатеричное число отправляется на запись, машина понимает что к чему и меняет байты в памяти местами, скрывая это от глаз. Вот такой трюк.).

Рассмотренный нами сценарий называется проблемой “NUXI”, потому что последовательность “UNIX” интерпретируется как “NUXI” на машинах с различным порядком хранения байтов. Опять же, эта проблема возникает только при обмене данными — каждая машина имеет внутреннюю совместимость.

Обмен данными между машинами с различным порядком хранения байтов

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

Решение 1: Использовать общий формат

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

Для конвертирования данных в соответствии с сетевым порядком хранения байтов, машины вызывают функцию hton() (host-to-network). На машинах с прямым порядком хранения эта функция не делает ничего, но мы не будем говорить здесь об этом (это может разозлить машины с обратным порядком хранения 🙂 ).

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

Точно также существует функция ntoh() (network-to-host), которая используется для чтения данных из сети. Вы должны использовать ее, чтобы быть уверенными, что правильно интерпретируете сетевые данные в формат хоста. Вы должны знать тип данных, которые принимаете, чтобы расшифровать их правильно. Функции преобразования имеют следующий вид:

Помните, что один байт — это один байт и порядок не имеет значения.

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

Решение 2: Использования маркера последовательности байтов (Byte Order Mark — BOM)

Этот подход подразумевает использование некого магического числа, например 0xFEFF, перед каждым куском данных. Если Вы считали магическое число и его значение 0xFEFF, значит данные в том же формате, что и у Вашей машины и все хорошо. Если Вы считали магическое число и его значение 0xFFFE, это значит, что данные были записаны в формате, отличающемся от формата вашей машины и Вы должны будете преобразовать их.

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

Во-вторых, BOM добавляет накладные расходы для всех передаваемых данных. Даже в случае передачи 2 байт информации Вы должны добавлять к ним 2 байта маркера BOM. Пугающе, не так ли?

Unicode использует BOM, когда сохраняет многобайтные данные (некоторые кодировки Unicode могут иметь по 2, 3 и даже 4 байта на символ). XML позволяет избежать этой путаницы, сохраняя данные сразу в UTF-8 по умолчанию, который сохраняет информацию Unicode по одному байту за раз. Почему это так круто?

Повторяю в 56-й раз — потому что проблема порядка хранения не имеет значения для единичных байт.

Опять же, в случае использования BOM может возникнуть другие проблемы. Что, если Вы забудете добавить BOM? Будете предполагать, что данные были отправлены в том же формате, что и Ваши? Прочитаете данные и, увидев что они “перевернуты” (что бы это не значило), попытаетесь преобразовать их? Что, если правильные данные случайно будут содержать неправильный BOM? Эти ситуации не очень приятные.

Почему вообще существует эта проблема? Нельзя ли просто договориться?

Ох, какой же это философский вопрос. Каждый порядок хранения байтов имеет свои преимущества. Машины с порядком следования от младшего к старшему позволяют читать младший байт первым, не считывая при этом остальные. Таким образом можно легко проверить является число нечетным или четным (последний бит 0), что очень здорово, если Вам необходима такая проверка. Машины с порядком от старшего к младшему хранят данные в памяти в привычном для человека виде (слева направо), что упрощает низкоуровневую отладку.

Так почему же все просто не договорятся об использовании одной из систем? Почему одни компьютеры пытаются быть отличными от других? Позвольте мне ответить вопросом на вопрос: почему не все люди говорят на одном языке? Почему в некоторых языках письменность слева направо, а у других справа налево?

Иногда системы развиваются независимо, а в последствии нуждаются во взаимодействии.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *