Числа со знаком и дополнительный код
Помимо того, что процессор работает с двоичными числами, эти числа могут быть со знаком или без знака. Если число без знака, то оно просто представляет собой результат перевода десятичного числа в двоичный вид. Все биты в таком числе являются информационными и оно может принимать только неотрицательные значения.
Для представления чисел со знаком используется специальное кодирование. Старший бит в этом случае обозначает знак числа. Если знаковый бит равен нулю, то число положительное, иначе — отрицательное. Понятно, что положительное число со знаком будет выглядеть точно так же, как и число без знака.
С отрицательными числами чуть сложнее. Исторически для представления отрицательных чисел в компьютерах использовались разные виды кодирования: прямой, обратный и дополнительный код. В настоящее время наиболее часто используется дополнительный код, в том числе и в процессорах x86.
Чтобы сделать из положительного числа отрицательное, необходимо проинвертировать все его биты (0 заменяем на 1, а 1 заменяем на 0) и затем к младшему разряду прибавить единицу. Например, представим -5 в дополнительном коде:
В обратную сторону переводится точно также 🙂
Синтаксис FASM
Для записи отрицательного числа в программе на ассемблере используется символ ‘-‘, например:
x db -5
Кстати, это работает и с числами в других системах счисления, и даже с символами 🙂
y db -25h
z db -77o
k db -101b
s db -'a'
Со знаковыми и беззнаковыми числами нужно быть внимательным, потому что только вы знаете, какие числа используются в вашей программе! Процессору абсолютно по барабану, какие данные он обрабатывает, поэтому невнимательность может привести к ошибке. Один и тот же байт может интерпретироваться по-разному, в зависимости от того со знаком число или без. Например, числу со знаком -5 соответствует число без знака 251:
Диапазоны значений чисел со знаком и без
При программировании на ассемблере (как, впрочем, и на многих других языках) необходимо учитывать ещё один важный момент. А именно — ограничение диапазона представления чисел. Например, если размер беззнаковой переменной равен 1 байт, то она может принимать всего 256 различных значений. Это означает, что мы не сможем представить с её помощью число, больше 255 (111111112). Для такой же переменной со знаком максимальным значением будет 127 (011111112), а минимальным -128 (100000002). Аналогично определяется диапазон для 2- и 4-байтных переменных.
Кстати, так как процессор Intel 8086 был 16-битным и обрабатывал за одну команду 16-бит, то 16-битная переменная называется слово (word), а 32-битная — двойное слово (double word, dword). Эти названия сохранились в ассемблере даже для 32-битных процессоров (и в WIN32 API, например). И от них же происходят названия директив dw (Define Word) и dd (Define Dword). Ну а db — это Define Byte.
Для наглядности вот табличка диапазонов чисел:
Размер переменной |
Число без знака | Число со знаком | ||
---|---|---|---|---|
min | max | min | max | |
байт | 00000000 | 11111111 | 10000000 | 01111111 |
0 | 255 | -128 | 127 | |
слово | 00000000 00000000 | 11111111 11111111 | 10000000 00000000 | 01111111 11111111 |
0 | 65 535 | -32 768 | 32 767 | |
двойное слово |
0000…0000 | 1111…1111 | 1000…0000 | 0111…1111 |
0 | 4 294 967 295 | -2 147 483 648 | 2 147 483 647 | |
и т.д. | … | … | … | … |
Если результат какой-то операции выйдет за пределы диапазона представления чисел, то случится переполнение и результат будет некорректным. (Например, при сложении двух положительных чисел, можно получить отрицательное число!) Поэтому нужно быть внимательным при программировании и предусмотреть обработку таких ситуаций, если они могут возникнуть.