Выяснить, как взаимодействуют сети, hex и ascii - PullRequest
1 голос
/ 11 января 2012

Недавно я был назначен на проект C ++, включающий передачу информации между компьютерами по протоколу UDP.Когда приходит пакет, у меня есть программа, которая принимает данные и может отображать их в виде необработанной шестнадцатеричной строки.Однако я изо всех сил пытаюсь понять, как именно весь этот процесс должен работать.Предполагается, что шестнадцатеричная строка содержит несколько полей (например, массив из 4 символов, некоторые float_32s и некоторые uint_32s).

Как мне перевести разделы этой строки в правильные типы переменных?Первое значение, название ASCII, было достаточно простым;первые восемь символов в шестнадцатеричной строке представляют собой шестнадцатеричное представление слова ASCII (шестнадцатеричный код 0x45 может быть переведен непосредственно в заглавную букву E).Но следующее значение, 32-разрядное число с плавающей запятой, не имеет для меня никакого смысла.Какова связь между шестнадцатеричным значением «42 01 33 33» и значением с плавающей точкой «32,3» (данный пример)?

Я немного над головой, я чувствую, что мне не хватаетнекоторая важная информация о том, как работают системы счисления.

Ответы [ 3 ]

2 голосов
/ 11 января 2012

Все типы в C имеют представление (которое для большинства типов определяется конкретной реализацией). Большинство реализаций C используют IEEE 754 для представления плавающих типов (это может фактически быть требованием для C и C ++, но из памяти это не так). Статья в Википедии объясняет, как плавающие типы представлены в памяти. В большинстве реализаций C и C ++ float - это 32-битный тип, а double - это 64-битный тип. Следовательно, в этих реализациях float имеет ширину 4 байта, а double имеет ширину 8 байтов.

Будьте осторожны, поскольку порядок байтов может быть другим. Некоторые архитектуры хранят плавающий тип с прямым порядком байтов, другие с большим порядком байтов. Также есть статья в Википедии о endianness тоже.

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

unsigned char rep[] = { 0x42, 0x01, 0x33, 0x33 };
float someFloat;

if (sizeof(someFloat) == 4)
{
    memcpy(&someFloat, rep, sizeof(someFloat));
}
else
{
    // throw an exception or something
}

Существуют и другие способы копирования байтов в плавающий тип, но будьте осторожны с & lsquo; нарушением правил & rsquo; (печатание типа и т. д.). Кроме того, если полученное значение является неправильным, это может быть связано с неправильным порядком байтов, и поэтому вам необходимо скопировать байты в обратном порядке, чтобы 4-й байт в представлении был 1-м байтом с плавающей запятой.

1 голос
/ 11 января 2012

Если у вас есть шестнадцатеричное значение:

42 01 33 33

Это эквивалент

0100 0010 0000 0001 0011 0011 0011 0011

в двоичном коде.

Теперь есть плавающая точкастандарт, называемый IEEE 754 , который говорит вам, как форматировать число с плавающей запятой в двоичный или обратно.

Суть в том, что первый бит является знаком (положительное / отрицательное число)следующие 8 бит - показатель степени, а последние 23 - мантисса.Именно так компьютер сохраняет внутренние числа с плавающей запятой, поскольку он может хранить только 1 и 0.

Если вы сложите все это вместе, как указано в IEEE, вы получите 32.3.

0 голосов
/ 11 января 2012

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

Целое число без знака: на самом деле это самое простое. Его типичное представление в принципе работает как наша обычная десятичная система, за исключением того, что «цифры» являются байтами и могут иметь 256 различных значений.

Если вы посмотрите на десятичное число, например 3127, вы увидите три цифры. Наименее значащая цифра - последняя (в данном случае цифра 7). Наименее значимое означает, что если вы измените его на 1, вы получите минимальное изменение значения (а именно 1). Наиболее значимой цифрой в этом примере является цифра 3 слева: если вы измените эту цифру на 1, вы сделаете максимальное изменение значения, а именно изменение 1000. Поскольку имеется 10 различных цифр (от 0 до 9), число, представленное "3127", равно 3 * 10 * 10 * 10 + 1 * 10 * 10 + 2 * 10 + 7. Обратите внимание, что это просто условное обозначение, что наиболее значимая цифра стоит первой; Вы также можете определить, что наименьшая значащая цифра идет первой, а затем эта цифра будет записана как «7213».

Теперь в большинстве кодирований числа без знака работают точно так же, за исключением того, что "цифры" являются байтами, и поэтому вместо основания 10 у нас есть основание 256. Кроме того, в отличие от десятичных чисел, не существует универсального соглашения о том, является ли наиболее значимое байт (MSB) или младший байт (LSB) идет первым; оба соглашения используются в разных протоколах или форматах файлов.

Например, в 4-байтовом (то есть 32-битном) беззнаковом int с MSB сначала (также называемом кодированием с прямым порядком байтов), значение 1000 = 0 * 256 ^ 3 + 0 * 256 ^ 2 + 3 * 256 + 232 будет представлен четырьмя байтовыми значениями 0, 0, 3, 232 или шестнадцатеричным 00 00 03 E8. Для кодирования с прямым порядком байтов (сначала LSB) это будет E8 03 00 00. И как 16-битное целое число, это будет просто 03 E8 (с прямым порядком байтов) или E8 03 (с прямым порядком байтов).

Для целых чисел со знаком наиболее часто используемое представление - это дополнение к двум. По сути, это означает, что если старший значащий бит равен 1 (т. Е. Старший значащий байт равен 128 или больше), последовательность байтов не кодирует число, как написано выше, а вместо этого отрицательное число, полученное вычитанием 2 ^ (бит) отсюда, где (биты) - количество бит в числе. Например, в 16-битном int со знаком последовательность FF FF не равна 65535, как это было бы в 16-битном целом без знака, а скорее 65535-2 ^ 16 = -1. Как и в случае беззнаковых целых, вы должны различать байты с прямым порядком байтов и байты с прямым порядком байтов. Например, -3 будет FF FD в 16-битном порядке с прямым порядком байтов, но FD FF в 16-битном порядке с прямым порядком байтов.

Плавающая точка немного сложнее; сегодня обычно используется формат, определенный IEEE / IEC. В основном числа с плавающей запятой имеют форму знака * (1.mantissa) * 2 ^ экспонента, а знак, мантисса и экспонента хранятся в разных подполях. Опять же, есть формы с прямым порядком байтов и с прямым порядком байтов.

...