Почему значения DWORD обычно представлены в шестнадцатеричном формате? - PullRequest
8 голосов
/ 14 апреля 2011

Я пытаюсь понять, почему значение DWORD часто описывается в шестнадцатеричном формате на MSDN.

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

В любом случае, я мог бы использовать некоторые пояснения или ресурсы о том, как запомнить разницу между DWORD, целыми числами без знака, байтами, битами, WORD и т. Д.* В заключение, мои вопросы: 1) Почему DWORD представлены в шестнадцатеричном формате?2) Можете ли вы предоставить ресурсы о различиях между числовыми типами данных и причинах их создания?

Ответы [ 5 ]

9 голосов
/ 14 апреля 2011

Все в компьютере - это набор из 0 и 1. Но писать весь DWORD в двоичном виде довольно утомительно:

00000000 11111111 00000000 11111111

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

// each octal digit is exactly 3 binary digits
01 010 100 binary  =  124 octal

// each hexadecimal digit is exactly 4 binary digits
0101 0100 binary   =  54 hexadecimal

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

Обычное сокращение для определения используемой базы:

  1234543 = decimal
 01234543 = octal (leading zero)
0x1234543 = hexadecimal (starts with 0x)

Что касается вашего вопроса о BYTE, WORD, DWORD и т.д ...

Компьютеры начали с немного. Только 1 или 0. У него была камея в оригинальном Троне.

Байты имеют длину 8 бит (хорошо, когда-то были 7-битные байты, но мы можем их игнорировать). Это позволяет вам иметь число от 0 до 255 или число со знаком от -128 до 127. Лучше, чем просто 1/0, но все же ограничено. Возможно, вы слышали ссылки на «8-битные игры». Это то, что мы имеем в виду. Система была построена вокруг байтов.

Затем компьютеры выросли до 16-разрядных регистров. Это 2 байта, и стало известно как СЛОВО (нет, я не знаю почему). Теперь числа могут быть от 0-65535 или от -32768 до 32767.

Мы продолжали нуждаться в большей мощности, и компьютеры были расширены до 32-разрядных регистров. 4 байта, 2 слова, также известные как DWORD (двойное слово). По сей день вы можете заглянуть в «C: \ Windows» и увидеть каталог для «system» (старые 16-разрядные компоненты) и «system32» (новые 32-разрядные компоненты).

Затем пришло КВОРД (четверное слово). 4 слова, 8 байт, 64 бита. Вы когда-нибудь слышали о Nintendo-64? Вот откуда пришло название. Современная архитектура сейчас здесь. Внутренние компоненты процессора содержат 64-битные регистры. Обычно на таком процессоре можно запустить 32- или 64-разрядную операционную систему.

Это охватывает Бит, Байт, Слово, Меч. Это необработанные типы, и они часто используются для флагов, битовых масок и т. Д. Если вы хотите сохранить фактическое число, лучше использовать целое число со знаком / без знака, long и т. Д.

Я не охватывал числа с плавающей запятой, но, надеюсь, это поможет с общей идеей.

4 голосов
/ 14 апреля 2011

Константы DWORD обычно записываются в шестнадцатеричном виде, когда они используются в качестве флагов, которые могут быть ИЛИ вместе по битам. Это легче увидеть, что это так. Вот почему вы видите 0x01, 0x02, 0x04, 0x08, 0x10, 0x20 и т. Д. Программисты просто распознают эти значения как двоичные представления только с одним установленным битом.

Когда это перечисление, вы видите 0x01, 0x02, 0x03 и т. Д. Они часто по-прежнему записываются в шестнадцатеричном виде, потому что программисты склонны к этим привычкам!

1 голос
/ 25 апреля 2011

Только для записи, 16-битные данные без знака называются WORD, потому что в настоящее время компьютеры имеют 16-битные регистры.

В истории компьютеров, 8-битные данные, где самые большие данные вы можете хранить в регистре. Поскольку он мог хранить символ ascii, его обычно называли CHAR.

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

Итак, на некоторых компьютерах использование другого ЦП WORD обычно относится к размеру регистра. На процессоре Saturn, который использует 64-битный регистр, WORD составляет 64 бита.

Когда вышли 32-битные процессоры x86, WORD остался 16-битным из соображений совместимости, и был создан DWORD, чтобы расширить его до 32-битных. То же самое верно для QWORD и 64 бит.

Что касается того, почему шестнадцатеричное обычно используется для описания СЛОВА, оно имеет отношение к природе определения СЛОВА, которое связано с его происхождением регистра. В программировании на ассемблере вы используете шестнадцатеричное для описания данных, потому что процессоры знают только двоичные числа (0 и 1). А шестнадцатеричный - это более компактный способ использовать двоичный файл и при этом сохранять некоторые его свойства.

0 голосов
/ 07 декабря 2012

У вас очень интересный и хитрый вопрос.

Короче говоря, существует два драйвера, которые приводят к существованию семей конкурирующих типов - на основе DWORD и на основе int:

1) Желание иметь перекрестную форму с одной стороны и строжайший размер с другой стороны.

2) Народный консерватизм.

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

Во-первых, существует такое понятие, как машинное слово. Машинное слово - это кусочек двоичных данных ограниченного размера, естественный для обработки в конкретном процессоре. Таким образом, размер машинного слова вряд ли зависит от процессора и в целом равен размеру общих внутренних регистров процессора. Обычно он может быть разделен на две равные части, которые также могут быть доступны процессору как независимые порции данных. Например, на процессорах x86 размер машинного слова составляет 32 бита. Это означает, что все общие регистры (eax, ebx, ecx, edx, esi, edi, ebp, esp и eip) имеют одинаковый размер - 32 бита. Но многие из них могут быть доступны как часть реестра. Например, вы можете использовать eax как 32-битный блок данных, ax, как 16-битный блок данных или даже как 8-битный блок данных. Но физически это не 32-битный регистр. Я думаю, что вы можете найти очень хорошее представление об этом поле в Википедии (http://en.wikipedia.org/wiki/Word_(computer_architecture)). Короче говоря, машинное слово - это то, какой объем битовых данных можно использовать в качестве целочисленного операнда для одной инструкции. Даже сегодня разные архитектуры процессоров имеют разные машинные слова). размер.

Хорошо, у нас есть некоторое понимание компьютерного слова. Это время, чтобы вернуться в историю вычислений. Первые популярные процессоры Intel x86 имели 16-битный размер слова. Он появился на рынке в 1978 году. В то время ассемблер был очень популярен, если не основным языком программирования. Как вы знаете, ассемблер - это просто очень тонкая оболочка для родного языка процессора. Из-за этого это полностью зависит от оборудования. И когда Intel выпустила на рынок новый процессор 8086, первое, что им было необходимо для достижения успеха, это подтолкнуть на рынок ассемблер для нового процессора. Никто не хочет процессор, который никто не знает, как программировать. И когда Intel дала имена для различных типов данных в ассемблере для 8086, они сделали очевидный выбор и назвали 16-битный блок данных словом, потому что машинное слово 8086 имеет 16-битный размер. Половина машинного слова была названа байтом (8-разрядным), а два слова, использованные в качестве одного операнда, назывались двойным словом (32-разрядным). Intel использовала эти термины в руководствах по процессорам и в мнемонике ассемблера (db, dw и dd для статического распределения байтов, слов и двойных слов).

Прошли годы, и в 1985 году Intel перешла от 16-битной архитектуры к 32-битной архитектуре с введением процессора 80386. Но в то время было огромное количество разработчиков, которые привыкли к тому, что это слово является 16-битным значением. Помимо того, что было написано огромное количество мягких слов с истинным верованием, это слово является 16-битным. И многие из уже написанного кода опираются на тот факт, что слово является 16-битным. Из-за этого, помимо факта, что размер машинного слова фактически изменился, нотация осталась прежней, за исключением того факта, что новый тип данных поступил на ассемблер - четырехугольное слово (64-разрядное), потому что инструкция, которая опирается на две машины слова остались прежними, но машинное слово было расширено. Таким же образом двойное четырехзначное слово (128-битное) появилось теперь с 64-битной архитектурой AMD64. В результате мы имеем

byte    =   8 bit
word    =  16 bit
dword   =  32 bit
qword   =  64 bit
dqword  = 128 bit

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

С другой стороны, в то же времяс каждым годом языки высокого уровня становились все более популярными.И поскольку эти языки были разработаны с учетом кроссплатформенного приложения, они смотрели на размеры своих внутренних типов данных с совершенно иной точки зрения.Если я правильно понимаю, ни один язык высокого уровня не утверждает, что некоторые из его внутренних типов данных имеют фиксированный постоянный размер, который никогда не изменится в будущем.Давайте не будем смотреть на C ++ как на примере.Стандарт C ++ говорит, что:

"The fundamental storage unit in the C++ memory model is the byte. A byte is at 
least large enough to contain any member of the basic execution character set and 
is composed of a contiguous sequence of bits, the number of which is implementa-
tion-defined. The least significant bit is called the low-order bit; the most 
significant bit is called the high-order bit. The memory available to a C++ program
consists of one or more sequences of contiguous bytes. Every byte has a unique 
address."

Итак, мы можем видеть удивительную информацию - в C ++ даже байты не имеют постоянного размера.Таким образом, даже если мы привыкли думать, что размер - 8 бит, в соответствии с C ++ может быть не только 8, но и 9, 10, 11, 12 и т. Д. Размером.А может быть даже 7 бит.

"There are five signed integer types: “signed char”, “short int”, “int”, and 
“long int”., and “long long int”. In this list, each type provides at least as 
much storage as those preceding it in the list. Plain ints have the natural size
suggested by the architecture of the execution environment; the other signed 
integer types are provided to meet special needs."

В этом цитировании приводятся два основных утверждения:

1) sizeof (char) <= sizeof (short) <= sizeof (int) <= sizeof (long) <= sizeof (long long) </p>

2) Простые целые имеют натуральный размер, предложенный архитектурой среды исполнения.Это означает, что int должен иметь размер машинного слова в архитектуре целевого процессора.

Вы можете просмотреть весь стандартный текст C ++, но вам не удастся найти что-то вроде «размер int равен 4 байтам» или «длина»долго 64 бит ".Размер отдельных целочисленных типов C ++ может изменяться при переходе от одной архитектуры процессора к другой и при переходе от одного компилятора к другому.Но даже когда вы пишете программу на с ++, вы периодически сталкиваетесь с необходимостью использовать типы данных с хорошо известным постоянным размером.

По крайней мере, более ранние разработчики компиляторов следовали этим стандартным требованиям.Но теперь мы можем видеть, что консерватизм людей входит в игру еще раз.Раньше считалось, что int является 32-разрядным и может хранить значения в диапазоне от –2 147 483 648 до 2 147 483 647.Ранее, когда промышленность перешла границу между 16-битной и 32-битной архитектурами.Второе требование было строго исполнено.И когда вы использовали компилятор C ++ для создания 16-битной программы, компилятор использовал int с 16-битным размером, который является «естественным размером» для 16-битных процессоров, и, наоборот, когда вы использовали другой компилятор C ++ для создания 32-битной программы, ноиз того же исходного кода компилятор использовал int с 32-разрядным размером, который является «естественным размером» для 32-разрядных процессоров.В настоящее время, если вы посмотрите, например, на компилятор Microsoft C ++, вы обнаружите, что он будет использовать 32-разрядный тип int независимо от целевой архитектуры процессора (32-разрядный или 64-разрядный) только потому, что раньше люди думали, что int является32-бит!

Суммируя, мы можем видеть, что есть два семейства типов данных - на основе dword и на основе int.Мотивация для второго очевидна - разработка кроссплатформенных приложений.Мотивация для первого - это все случаи, когда учет размеров переменных имеет смысл.Например, среди прочего мы можем упомянуть следующие случаи:

1) Вам нужно иметь какое-то значение в заранее определенном известном диапазоне, и вам нужно использовать его класс или другую структуру данных, которая будет заполнять огромное количество экземпляров.во время выполнения.В этом случае, если вы будете использовать int-ориентированные типы для хранения этого значения, это будет иметь недостаток в огромных накладных расходах памяти на некоторых архитектурах и потенциально может нарушить логику на другой.Например, вам нужно манипулировать значениями в диапазоне от 0 до 1000000. Если вы будете использовать int для его хранения, ваша программа будет корректно вести себя, если int будет 32-битной, будет иметь 4-байтовые издержки памяти на каждый экземпляр значения, если intбудет 64-битным и не будет корректно работать, если int будет 16-битным.

2) Данные, задействованные в следующей работе.Чтобы иметь возможность правильно обрабатывать ваш сетевой протокол на разных компьютерах, вам нужно будет указать его в простом формате, основанном на размере, который будет описывать все пакеты и заголовок побитно.Ваша сетевая связь будет полностью прервана, если на одном ПК ваш заголовок протокола будет иметь длину 20 байт с 32-разрядным, а на другом компьютере он будет иметь длину 28 байт с 64-разрядным целым.

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

4) Вам необходимо хранить значения, которые будут использоваться для связи с устройствами.Каждое устройство имеет свою спецификацию, которая описывает, какое устройство ввода требуется для ввода и в какой форме оно будет обеспечивать вывод.Если для устройства требуется 16-разрядное значение в качестве входного, оно должно получать одинаково 16-разрядное значение независимо от размера int и даже независимо от размера машинного слова, используемого процессором в системе, в которой установлено устройство.

5) Ваш алгоритмопирается на целочисленную логику переполнения.Например, у вас есть массив из 2 ^ 16 записей, и вы хотите, чтобы он последовательно и последовательно просматривал его и обновлял значения записей.Если вы будете использовать 16-битный int, ваша программа будет работать отлично, но, скорее всего, вы переходите на использование 32-битного int, и у вас будет доступ к индексу массива вне диапазона.

Из-за этого Microsoft использует оба семейства данных.типы.Основанные на Int типы в случае, когда фактический размер данных не имеет большого значения, и основанные на DWORD в случаях, когда это имеет.И даже в этом случае Microsoft определяет оба как макросы, чтобы обеспечить возможность быстро и легко адаптировать систему виртуальных типов, используемую Microsoft, к конкретной архитектуре процессора и / или компилятору, назначая ей правильный эквивалент C ++.

Iнадеюсь, что я достаточно хорошо рассмотрел вопрос о происхождении типов данных и их различиях.

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

1) Если мы используем двоичные типы данных строгого размера, то вполне ожидаемо, что мы можем захотеть взглянуть на них в двоичной форме.

2) ЭтоЗначения легко понять значения битовых масок, когда они закодированы в двоичном виде.Согласитесь, что гораздо проще понять, какой бит установлен и какой бит сбрасывается, если значение в следующей форме

1100010001011001

, тогда если оно будет закодировано в следующей форме

50265

3) Данные, закодированные в двоичной форме и описанные одним значением на основе DWORD, имеют постоянную длину, когда те же данные, закодированные в десятичной форме, будут иметь переменную длину.Обратите внимание, что даже когда небольшое число кодируется в двоичной форме, полное описание значения предоставляется

0x00000100

вместо

0x100

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

Итак, мы решили, что хотим использовать двоичное кодирование.У нас есть три варианта: использовать обычное двоичное кодирование, использовать восьмеричное кодирование и использовать шестнадцатеричное кодирование.Peple предпочитает использовать шестнадцатеричное кодирование, потому что оно самое короткое из набора доступных кодировок.Просто сравните

10010001101000101011001111000

и

0x1234568

Можете ли вы быстро найти количество битов, которое установлено в следующем значении?

00000000100000000000000000000

и в следующем?

0x00100000

Во втором случае вы можете быстро разделить число на четыре разделенных байта

0x00 0x10 0x00 0x00
   3    2    1    0

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

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

0 голосов
/ 14 апреля 2011

Чтобы уточнить ответ Тима, это потому, что преобразовать шестнадцатеричный код в двоичный и обратно очень просто - каждая шестнадцатеричная цифра состоит из 4 двоичных цифр:

0x1 = 0001
0x2 = 0010
...
0xD = 1101
0xE = 1110
0xF = 1111

Итак, 0x2D = 0010 1101

...