Как вывести число по байтам

Перевести байты в килобайты или наоборот

Перевести число, введенное пользователем, в байты или килобайты в зависимости от его выбора.

В данной задаче пользователь должен ввести два значения: само число и как-либо указать, во что он хочет его перевести (в байты или килобайты). Пусть выбор способа перевода указывается с помощью одного из двух символов. Например, если пользователь введет букву «b», то число будет переводиться в байты, а если букву «k», то в килобайты. Тогда алгоритм решения задачи будет следующим:

  1. Ввести число.
  2. Указать направление перевода.
  3. Если выбран перевод в байты, то надо умножить число на 1024.
  4. Если выбран перевод в килобайты, то надо разделить число на 1024.

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

Данную задачу проще решить с помощью оператор выбора case , а не if .

Читайте также:  Как можно отстирать краску для волос от полотенца

Pascal

Язык Си

Python

КуМир

Basic-256

var
n: word;
c: char;
begin
write(‘Число: ‘);
readln(n);
write(‘Перевести в байты(b) или килобайты(k): ‘);
readln(c);
if c = ‘b’ then
writeln(n,’Кб = ‘, n*1024, ‘Б’)
else
if c = ‘k’ then
writeln(n,’Б = ‘, n/1024:3:2, ‘Кб’);
end.

// 2-й вариант (через оператор case):

var
n: word;
c: char;
begin
write(‘Число: ‘);
readln(n);
write(‘Перевести в байты(b) или килобайты(k): ‘);
readln(c);
case c of
‘b’: writeln(n,’Кб = ‘, n*1024, ‘Б’);
‘k’: writeln(n,’Б = ‘, n/1024:3:2, ‘Кб’);
end;
end.

Число: 5000
Перевести в байты(b) или килобайты(k): b
5000Кб = 5120000Б

Число: 5000
Перевести в байты(b) или килобайты(k): k
5000Б = 4.88Кб

main() <
int n;
char c;
printf(«Число: «);
scanf(«%d%*c»,&n);
printf(«Перевести в байты (b) или килобайты (k): «);
scanf(«%c»,&c);
if (c == ‘b’) printf(«%d Кб = %d байт», n, n*1024);
else if (c == ‘k’) printf(«%d байт = %.2f Кб», n, n/1024.0);
printf(«\n»);
>

// С помощью оператора выбора switch:

main() <
int n;
char c;
printf(«Число: «);
scanf(«%d%*c»,&n);
printf(«Перевести в байты (b) или килобайты (k): «);
scanf(«%c»,&c);
switch (c) <
case ‘b’:
printf(«%d Кб = %d байт», n, n*1024);
break;
case ‘k’:
printf(«%d байт = %.2f Кб», n, n/1024.0);
break;
>
printf(«\n»);
>

Число: 10
Перевести в байты (b) или килобайты (k): b
10 Кб = 10240 байт

Число: 10000
Перевести в байты (b) или килобайты (k): k
10000 байт = 9.77 Кб

n = int(input(«Число: «))
c = input(«Перевести в байты (b) или килобайты (k): «)
if c == ‘b’:
print(«%dКб = %d байт» % (n, n*1024))
elif c == ‘k’:
print(«%d байт = %.2fКб» % (n, n/1024))

Число: 10000
Перевести в байты (b) или килобайты (k): k
10000 байт = 9.77Кб

Число: 45
Перевести в байты (b) или килобайты (k): b
45Кб = 46080 байт

| Использование инструкции «если-иначе»:

алг байты
нач
цел n
сим c
вывод «Число: »
ввод n
вывод «Перевод в байты(б) или килобайты(к): »
ввод c
если c = «б» то
вывод n, «Кб = «, n*1024, «Б»
иначе
если c = «к» то
вывод n, «Б = «, n/1024, «Кб»
все
все
кон

| Использование инструкции «выбор»:

алг байты
нач
цел n
сим c
вывод «Число: »
ввод n
вывод «Перевод в байты(б) или килобайты(к): »
ввод c
выбор
при c = «б»: вывод n, «Кб = «, n*1024, «Б»
при c = «к»: вывод n, «Б = «, n/1024, «Кб»
все
кон

Число: 45
Перевод в байты(б) или килобайты(к): б
45Кб = 46080Б

Число: 1045
Перевод в байты(б) или килобайты(к): к
1045Б = 1.020508Кб

input n
input «Перевести в байты(б) или килобайты(к): «, c$
if c$ = «б» then
print n*1024 + «Б»
else
if c$ = «к» then print n/1024 + «Кб»
endif

34
Перевести в байты(б) или килобайты(к): б
34816Б

1000
Перевести в байты(б) или килобайты(к): к
0.976562Кб

Источник

Получить число из байтов

Помощь в написании контрольных, курсовых и дипломных работ здесь.

Получить массив байтов из int32_t
Собственно сабж! Самое элегантное решение, но как мне кажется не совсем безопасное это что-то.

Перевод байтов в число
Добрый день! Написал небольшую программу для связи с прибором через сом порт. Прибор измеряет.

Прием по modbus. Как указать число считываемых байтов
Добрый день. Пишу программу для обмена по modbus’у rtu , я slave , принимаю команды и формирую.

Добавлено через 4 минуты
Вариант из #2 не учитывает того, что старшие биты величин типа bytes[0] могут быть и не нулевыми. А так же «корявое» формирование констант, являющихся степенями двойки (хотя это уже и не критично)

Вариант из #3 является endian-зависимым и, строго говоря, противоречит strict aliasing rules, прописанным в стандарте (хотя код с вероятностью 99.9% будет рабочим — Оптимизация кода, нарушающего правила strict aliasing)

Решение

Приведу пример для десятичной системы, потом перейдем к вашему примеру.
Допустим надо выделить разряды из числа 1357. Для этого мы делим с остатком на 10, получаем 135 и остаток 7, 7 это нулевой разряд нашего числа, продолжаем 13 остаток 5, 5 первый разряд, 1 остаток 3, 0 остаток 1.
Как собрать число из разрядов?
Сумма 10^n*Xn; получим 10^0 * 7 + 10^1 * 5 + 10^2 * 3 + 10^3 * 1 = 1357.

Получение байтов из числа это фактически разложение числа на разряды в системе счисления с основанием 256.
bytes[0]= numder % 256;
bytes[1]= (number / 256) % 256;
bytes[2]= ((number / 256) / 256) % 256;
bytes[3]=(((number/ 256) / 256) / 256) % 256;
Логическое && в ваших выражениях это взятие остатка, а сдвиг вправо деление на 2.
Сдвиг вправо на один разряд это деление на 2, сдвиг 8 раз вправо деление на 2^8 = 256.
2 ^ 16 делим два раза на 256 и т. д.

Поэтому для получения числа обратно теперь основание не 10, а 256, сумма 256^n*Xn.
Получаем 256^0 * bytes[0] + 256^1 * bytes[1] + 256^2 * bytes[2] + 256^3 * bytes[3].

Погуглите системы счисления и перевод из одной системы в другую.
Аналогично делению, сдвиг влево равносилен умножению на 2, поэтому умножение на 256 можно заменить на сдвиг влево 8 раз и т. д. Тогда формула выше превращается в формулу из поста Evg.

Источник

Как с printf вывести 1 байт?

Вопрос банальный до ужаса тем не менее перерыв интернет и справки по си несмог понят как это сделать?

В общем нужно вывести 1 байт в виде беззнакового десятичного числа. Вот както так 121

по сути дела я пытаюсь строку из символьного массива вывести побайтно на экран . Но ведь числового типа данных в 1 байт не существует. А потом вдруг захочу вывести по 2 байта в виде одного числа? Это простая операция с данными но меня поставила в тупик

Помощь в написании контрольных, курсовых и дипломных работ здесь.

Как вывести 10 байт после определенных байт из файла
Здравствуйте. Есть к примеру файл с расширением *.bin, подскажите как реализовать вывод на экран 12.

Как вывести printf для струкутры
помогите, как вывести printf для струкутры w.sname,w.name и т.д вот мой код #include.

Как вывести без cout и printf
// ConsoleApplication14.cpp: определяет точку входа для консольного приложения. // #include.

Как вывести вектор через printf?
Есть вектор структур, но как его вывести через printf?

тип данных char имеет на борту 8 бит — 1 байт. Егор десятичное представление -127 — 128. unsigned char — беззнаковый тип данный 8 бит — 1 байт. Десятичное представление 0 — 255.

Добавлено через 3 минуты

Решение

Для формальной корректности нужно использовать формат %hhd или %hhu, а не %d или %u. Но в реальности при передаче параметров коротких типов (char, short) в функцию с эллипсом (с тремя точками) по стандарту языка компилятор сам построит преобразование в int, поэтому постфактум форматы %d и %u окажутся рабочими

Видите ли в чём дело. Я знаю что char это однобайтная переменная но printf %d выводит четыре байта а не один, и если у вас массив то вместо одного байта выведется огромное число считанное с последующих элементов. В том то и дело что он зацепляет соседние элементы в памяти. Я тоже заметил что если вывести обьявленную переменную то такой трюк срабатывает(видимо в памяти за переменной расчищено пространсвто) Но с массивом такое не прокатит.

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

«Байт» вот что касается предложения делать вот так: %hhd или %hhu h- это же вывод шестнадцатеричного числа или нет?
может это указание сколько байт целого числа вывести? Если это так было бы здорово. Может покажете где есть толковая исчерпывающая таблица и примеры таких способов вывода?

Добавлено через 14 минут
Вот попробуйте для примера вывести строку «privet ya vasya» каждую букву побайтно в виде беззнаковой цифры.
Должны получиться циферки соответствующие ascii или юникоду, или что там видовс использует.
Если начать выводить как элементы массива через %d вы получите милиарды.

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

Источник

Вывод разбитого по байтам числа

Добрый вечер, форумчане!

Прошу помочь разобраться в следующем вопросе. Tasm, MSDOS, .8086.
Читается несколько байт из поля chunkSize заголовка wav файла, в котором хранится значение-размер области данных самого файла. В самом файле это число разбито на 4 байта, слева-направо: младшие разряды к старшему. Т.е. для того, чтобы верно прочитать число и занести в буфер, нужно делать это справа-налево. С этим справился, однако возникла проблема с выводом числа на экран: так как число разбито на несколько байт, переводя каждый байт в десятичную сс и выводя на экран от старшего разряда к младшему, получается некорректное число. В моем случае показывается число 1 243 94 (что соответствует 01 F3 5E).
Я понимаю, что это число необходимо составить, домножая каждый разряд на 10h^n и складывая, однако регистры не позволяют вместить в себя хотя бы 10^4.
Соответственно, вопрос: можно ли реализовать это, дополнив мой код чем-нибудь, или надо искать другое решения для вывода этого числа?

Помощь в написании контрольных, курсовых и дипломных работ здесь.

Вывести по байтам числа
Подскажите, можно ли как нибудь, приспособить в мой код#include #include .

Загрузка разбитого спрайта
Доброго времени суток, в общем у меня есть изображения из фотошопа где есть разбитые спрайты, т.е.

Распознания разбитого стекла на смартфоне
Приветствую! Подскажите пожалуйста в какую сторону плыть чтоб решить данную проблему — Нужно.

Нужно вытащить данные приложений с разбитого телефона
Всем привет. Недавно разбил телефон meizu mx4. Потрескался экран и на нажатия никак не реагирует.

Источник

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

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

  • Проблема: Компьютеры, как и люди, говорят на разных языках. Одни записывают данные “слева направо” другие “справа налево”. При этом каждое устройство отлично считывает собственные данные — проблемы начинаются, когда один компьютер сохраняет данные, а другой пытается эти данные считать.
  • Решение: Принять некий общий формат (например, весь сетевой трафик передается в едином формате). Или всегда добавлять заголовок, описывающий формат хранения данных. Если считанный заголовок имеет обратный порядок, значит данные сохранены в другом формате и должны быть переконвертированы.

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

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

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

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

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

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

Основные концепции:

  • Данные (биты и байты или отметки на бумаге) сами по себе не имеют смысла. Они должны быть интерпретированы в какое-то абстрактное понятие, например, число.
  • Как и люди, компьютеры имеют различные способы хранения одного и того же абстрактного понятия (например, мы можем различными способами сказать “10”).

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

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

  • Бит имеет два состояния (включен или выключен, 1 или 0).
  • Байт — это последовательность из 8 бит. Крайний левый бит в байте является старшим. То есть двоичная последовательность 00001001 является десятичным числом девять. 00001001 = (2^3 + 2^0 = 8 + 1 = 9).
  • Биты нумеруются справа налево. Бит 0 является крайним правым и он наименьший. Бит 7 является крайним левым и он наибольший.

Мы можем использовать эти соглашения в качестве строительного блока для обмена данными. Если мы сохраняем и читаем данные по одному байту за раз, то этот подход будет работать на любом компьютере. Концепция байта одинаковая на всех машинах, понятие “байт 0” одинакова на всех машинах. Компьютеры также отлично понимают порядок, в котором Вы посылаете им байты — они понимают какой байт был прислан первым, вторым, третьим и т. д. “Байт 35” будет одним и тем же на всех машинах.

Так в чем же проблема — компьютеры отлично ладят с одиночными байтами, правда? Ну, все превосходно для однобайтных данных, таких как 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.

Теперь начинаются проблемы — если Вы читаете многобайтные данные, то где находится старший байт?

  • Машины с порядком хранения от старшего к младшему (прямой порядок) хранят старший байт первым. Если посмотреть на набор байтов, то первый байт (младший адрес) считается старшим.
  • Машины с порядком хранения от младшего к старшему (обратный порядок) хранят младший байт первым. Если посмотреть на набор байт, то первый байт будет наименьшим.

Такое именование имеет смысл, правда? Тип хранения от старшего к младшему подразумевает, что запись начинается со старшего и заканчивается младшим (Между прочим, английский вариант названий от старшего к младшего (Big-endian) и от младшего к старшему (Little-endian) взяты из книги “Путешествия Гулливера”, где лилипуты спорили о том, следует ли разбивать яйцо на маленьком конце (little-end) или на большом (big-end)). Иногда дебаты компьютеров такие же осмысленные 🙂

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

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

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

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

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

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

Итак, s это указатель на short int, и сейчас он указывает на позицию 0 (в которой хранится W). Что произойдет, когда мы считаем значение по указателю s?

  • Машина с прямым порядком хранения: Я думаю, short int состоит из двух байт, а значит я считаю их. Позиция s это адрес 0 (W или 0х12), а позиция s + 1 это адрес 1 (X или 0х34). Поскольку первый байт является старшим, то число должно быть следующим 256 * байт 0 + байт 1 или 256 * W + X, или же 0х1234. Я умножаю первый байт на 256 (2^8) потому что его нужно сдвинуть на 8 бит.
  • Машина с обратным порядком хранения: Я не знаю что курит мистер “От старшего к младшему”. Я соглашусь, что short int состоит из 2 байт и я считаю их точно также: позиция s со значение 0х12 и позиция s + 1 со значением 0х34. Но в моем мире первым является младший байт! И число должно быть байт 0 + 256 * байт 1 или 256 * X + W, или 0х3412.

Обратите внимание, что обе машины начинали с позиции s и читали память последовательно. Не никакой путаницы в том, что значит позиция 0 и позиция 1. Как и нет никакой путаницы в том, что являет собой тип short int.

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

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

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

И опять мы задаемся вопросом: какое значение хранится по адресу i?

  • Машина с прямым порядком хранения: тип int состоит из 4 байт и первый байт является старшим. Считываю 4 байта (WXYZ) из которых старший W. Полученное число: 0х12345678.
  • Машина с обратным порядком хранения: несомненно, int состоит из 4 байт, но старшим является последний. Так же считываю 4 байта (WXYZ), но W будет расположен в конце — так как он является младшим. Полученное число: 0х78563412.

Одинаковые данные, но разный результат — это не очень приятная вещь.

Проблема 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), что очень здорово, если Вам необходима такая проверка. Машины с порядком от старшего к младшему хранят данные в памяти в привычном для человека виде (слева направо), что упрощает низкоуровневую отладку.

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

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

Источник

Оцените статью