Значения хранятся в битах. Шестнадцатеричный формат - это один из способов отображения значения, хранимого в этих битах, как десятичного, восьмеричного и двоичного.
При условии 32-битного типа int
, значение 1023<sub>10</sub>
хранится в виде последовательности битов 00000000 00000000 00000011 11111111
, шестнадцатеричное представление которой равно 0x000003FF
.
Для такого значения требуется несколько байтов для хранения. Большинство систем, таких как x86, хранят многобайтовые значения, так что наименьший значащий байт идет первым, известный как порядок с прямым порядком байтов. Другие системы хранят многобайтовые значения, так что самый старший байт идет первым, известный как порядок с прямым порядком байтов. Предполагая, что наше целое число 1023
начинается с адреса p
, его байты будут адресованы, как показано ниже в каждой системе:
big-endian: p[0] p[1] p[2] p[3]
+----+----+----+----+
| 00 | 00 | 03 | FF |
+----+----+----+----+
little-endian: p[3] p[2] p[1] p[0]
Именно поэтому в вашей системе дисплей отображается с -1 3 0 0
вместо 0 0 3 -1
.
Что касается того, почему FF
отображается как -1
...
Существует несколько различных способов представления целочисленных значений со знаком, но их объединяет одно: самый левый бит используется для обозначения знака Если крайний левый бит равен 0, значение является положительным. Если крайний левый бит равен 1, значение является отрицательным. Предполагая 3-битный тип, они работают следующим образом:
Bits Two's Complement Ones' Complement Sign-Magnitude Unsigned
---- ---------------- ---------------- -------------- --------
000 0 0 0 0
001 1 1 1 1
010 2 2 2 2
011 3 3 3 3
100 -4 -1 -0 4
101 -3 -2 -1 5
110 -2 -3 -2 6
111 -1 -0 -3 7
x86 (наряду с подавляющим большинством других систем) использует дополнение до двух для представления целочисленных значений со знаком, поэтому целое число со всеми установленными битами равно интерпретируется как -1.
Когда вы используете %d
в вызове printf
, вы говорите printf
обрабатывать соответствующее значение как int
со знаком и форматировать его как последовательность десятичных цифр. Следовательно, байт, содержащий FF
, отформатирован как -1
в системе дополнения до двух. 1
Обратите внимание, что значение , сохраненное в x
, равно 1023<sub>10</sub>
(3ff<sub>16</sub>
) независимо от того, как упорядочены байты или как представлены целые числа со знаком. Если вы распечатаете шестнадцатеричное представление значения или x
с использованием
printf( "%08X\n", x ); // format output as hexadecimal
, оно будет отображаться как 0x000003FF
, а не 0xFF030000
.
Это на самом деле немного сложнее, чем это - значение в p[0]
сначала преобразуется из char
в int
, и для сохранения знака это преобразованное значение равно 0xFFFFFFFF
, что фактически передается в printf
.