Представление данных, биты и байты

Последнее обновление: 11.10.2023

На аппаратном уровне вся информация в компьютере представляет последовательность электрических сигналов. Например, в какой-то определенной ячейке памяти может быть иметься сильное напряжение, или оно может быть очень слабым. Для описания состояния сигнала информатике используется термина бит. По сути бит является наименьшей единицей информации в компьютере. Бит может иметь значение 1 (есть сигнал, что обычно соответствует напряжению от 2 до 5 V) или 0 (сигнал отсутствует или слабый - обычно от 0 до 2 V).

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

Один бит может принимать два значения: 0 и 1. Два бита вместе могут принимать четыре значения: 00, 01, 10 и 11. Три бита могут принимать восемь значений: 000, 001, 010, 011, 100, 101, 110 и 111. Обобщая, группа из n битов может принимать 2n значений. Таким образом, группа из 8 бит или 1 байт может представлять 28, то есть 256 уникальных значений. Таким образом, вся информация в компьютере фактически представляет последовательность бит.

Двоичная система

Поскольку бит может иметь только два значения - 1 и 0, то для записи битов применяют двоичную систему исчисления. Вообще система исчисления представляет способ записи чисел. Например, в поседневной жизни мы пользуемся десятичной системой исчисления. Это значит, что основанием этой системы является число 10, а каждый символ числа может иметь 10 вариантов значений - от 0 до 9. В десятичной системе каждое число можно представить как сумму цифер чисел, умноженных на 10 в степени, соответствующей порядковому номеру цифры в этом числе (нумерация начинается с нуля). Например, стандартное число 123 можно представить следующим образом:

12310 = 1 * 102 + 2 * 101 + 3 * 100 = 100 + 20 + 3

Или возьмем другое десятичное число - 123,45

123,4510 = 1 * 102 + 2 * 101 + 3 * 100  + 4 * 10-1 + 5 * 10-2 = 100 + 20 + 3 + 0,4 + 0,05

В двоичной системе каждый символ числа может иметь только два значения - 1 и 0, например, число 1101. Чтобы перевести число из двоичной системы в десятичную умножаем значение каждого бита (1 или 0) на число 2 в степени, равной номеру бита (нумерация битов идет от нуля):

// перевод двоичного числа 1101 в десятичную систему
1 * 23 + 1 * 22 + 0 * 21 + 1 * 20
=
1 * 8 + 1 * 4 + 0 * 2 + 1 * 1
=
8 + 4 + 0 + 1 
=
13

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

// перевод десятичного числа 13 в двоичную систему
13 / 2 = 6      // остаток 1 (13 - 6 *2 = 1)
6 / 2 = 3      // остаток 0 (6 - 3 *2 = 0)
3 / 2 = 1      // остаток 1 (3 - 1 *2 = 1)
1 / 2 = 0      // остаток 1 (1 - 0 *2 = 1)

Общий алгоритм состоит в последовательном делении числа и результатов деления на 2 и получение остатков, пока не дойдем до 0. Затем выстраиваем остатки в линию в обратном порядке и таким образом формируем двоичное представление числа. Конкретно в данном случае по шагам:

  1. Делим число 13 на 2. Результат деления - 6, остаток от деления - 1 (так как 13 - 6 *2 = 1)

  2. Далее делим результат предыдущей операции деления - число 6 на 2. Результат деления - 3, остаток от деления - 0

  3. Делим результат предыдущей операции деления - число 3 на 2. Результат деления - 1, остаток от деления - 1

  4. Делим результат предыдущей операции деления - число 1 на 2. Результат деления - 0, остаток от деления - 1

  5. Последний результат деления равен 0, поэтому завершаем процесс и выстраиваем остатки от операций делений, начиная с последнего - 1101

Шестнадцатиричная система

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

В шестнадцатеричной системе счисления двоичные числа разделены на группы по 4 бита. При 4 битах в группе количество возможных значений равно 24 или 16. Первым 10 из этих 16 чисел присваиваются цифры 0–9, а последним 6 — буквы A-F:

2-чная

16-чная

10-чная

0000

0

0

0001

1

1

0010

2

2

0011

3

3

0100

4

4

0101

5

5

0110

6

6

0111

7

7

1000

8

9

1001

9

9

1010

A

10

1011

B

11

1100

C

12

1101

D

13

1110

E

14

1111

F

15

Двоичное число 11101010 можно представить более компактно, разбив его на две 4-битные группы (1110 и 1010) и записав их в виде шестнадцатеричных цифр EA.

Алгоритм перевода из шестнадцатеричной системы в десятичную и обратно тот же, что и для двоичной, только вместо 2 используется число 16. Например, шестнадцатеричное число E6 можно представить следующим образом:

e6 = e * 161 + 6 * 160
 = 14 * 16 + 6
 = 23010 (десятичная система)
 = 1110 01102 (двоичная система)

А чтобы получить из 10-тичного числа 16-ричное, делим число на 16 и получаем остатки:

// перевод десятичного числа 230 в шестнадцатеричную систему
230 / 16 = 14    // остаток 6 (230 - 16 * 14 = 230 - 224) 
14 / 16 = 0    // остаток 14 или E в 16-й системе
// результат
0xE6

Чтобы указать, что число шестнадцатеричное, перед ним указываются символы 0X или 0x, например, 0xE6

Стоит отметить, что 4 бита, которые соответствуют одной шестнадцатеричной цифре, называется nibble или полубайт(слог, тертрада)

При работе с разными системами счисления легко запутаться. Например, какую систему в реальности представляет число 1010? Оно может равным образом представлять и десятичную, и двоичную, и шестнадцатеричную. И чтобы указать, что число относится к определенной системе счисления, используют различные обозначения. Так, для указания, что число является двоичным, перед число обычно ставится префикс 0b:

0b1010 - двоичное число (в десятичной системе равно 10, а в шестнадцатеричной - A)

Чтобы указать, что число является шестнадцатеричным, перед числом обычно ставится префикс 0x:

0x1010 - шестнадцатеричное число (в десятичной системе равно 4112, а в двоичной - 1000000010000)

Представление отрицательных чисел

Для представления отрицательных чисел обычно применяется two’s complement(дополнение до 2). С точки зрения математики чтобы получить отрицательный аналог числа надо от 0 (нуля) вычесть это число. Например, для получения -1 надо произвести операцию 0 - 1 = -1. С точки зрения архитектуры компьютера в качестве 0 выступает число 2N. В данном случае степень N представляет количество битов в числе.

Например, наше число состоит из 8 бит (1 байт), наподобие 0000 0001 (1 в десятичной системе). И мы хотим получить число -1. Для этого выполняем следующую операцию:

28 - 1 = 256 - 1 = 255

Но 255 - это в десятичной системе. А как это будет выглядеть в двоичной системе:

28 - 1 = 10000 0000 - 0000 0001 = 1111 1111

Таким образом, для 8 битное отрицательное число -1 в двоичной системе будет представлять 1111 1111

Аналогичная операция в шестнадцатеричной системе:

28 - 1 = 0x100 - 1 = 0xFF

Если же мы выполним обратную операцию - к 1111 1111 прибавим изначальное число 0000 0001, то мы получим степень двойки. Поэтому подобное представление отрицательных чисел и называется дополнение до 2-х.

Простой способ получить из положительного числа отрицательного и наборот (то есть фактически умножение на -1) заключается в том, чтобы инвертировать биты - биты 0 поменять на 1, а 1 на 0, и затем прибавить 1. Например, получим число -3. Для этого сначала возьмем двоичное представление числа 3:

310 = 0000 00112 

Инвертируем биты

~0000 0011 = 1111 1100

И прибавим 1

1111 1100 + 1 = 1111 1101

Таким образом, число 1111 1101 является двоичным представлением числа -3, что в шестнадцатеричной системе аналогично 0xFD

Другой пример, число 1 в двоичной системе равно 0b0000001. Чтобы получить число -1, сначала инвертируем биты:

~0000 0001 = 1111 1110

Далее прибавляем 1:

1111 1110 + 1 = 1111 1111

То есть число -1 в двоичной системе равно 1111 1111 или 0xFF (в шестнадцатеричной системе)

Подобным образом можно получить обратно число 1:

~1111 1111 = 0000 0000 
0000 0000  + 1 = 0000 0001

Соответственно, в зависимости от того, какое именно это число - положительное или отрицательно, интерпретировать это число можно по разному. Например, если число 1111 1111 рассматривается как положительное, то в десятичной системе оно равно 255. Если же оно рассматривается как отрицательное, то в десятичной системе оно равно -1.

Таким образом, 8-битные числа со знаком охватывают диапазон от -128 до 127, а 8-битные числа без знака - от 0 до 255.

Инструкции

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

Код операции — это один байт, определяющий основную операцию инструкции. Например, инструкция, которая копирует в регистр RAX число 1, имеет опкод C7 в шестнадцатеричной форме или 11000111 в двоичной форме. В зависимости от инструкции, ее операндов опкод меняется. Например, инструкция, которая копирует в регистр EAX число 1, имеет опкод B8 в шестнадцатеричной форме или 10111000 в двоичной форме. К опкодам инструкций следует добавить коды/значения операндов - регистра и чисел.

Написание машинного кода вручную возможно, но излишне громоздко. На практике вместо опкодов применяются так называемые мнемоники - человекочитаемые названия инструкций. Например, инструкция, которая копирует в регистр некоторое значение, имеет мнемонику mov (от слова "move" - помещать, поместить). А чтобы скопировать в регистр RAX число 1, в ассемблере NASM нам достаточно написано команду

mov rax, 1

А чтобы скопировать в регистр EAX число 1, нам достаточно написано команду

mov eax, 1

Это довольно удобнее, чем в бинарной форме вводить команды.

Программа состоит из набора подобных инструкций. Процессор запускает программы через цикл выборки-выполнения (fetch-execute cycle). Компьютер считывает по одной инструкции за раз. Для этого процессор обращается к специальному регистру - указателю команд (или регистр RIP), который также называется программным счетчиком (или PC) и который хранит адрес инструкции для выполнения. По сути, компьютер выполняет бесконечный цикл следующих операций:

  1. Считывает инструкцию с адреса памяти, указанного указателем инструкции - регистром IP/PC

  2. Декодирует инструкцию (т. е. выясняет, что означает инструкция)

  3. Перемещает указатель инструкций (регистр RIP/PC) к следующей инструкции

  4. Выполняет указанную инструкцию

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850