Где хранится информация о знаке числа?
Разбираюсь с ассемблером.
Хочется понять, где хранится информация о том, что то или иное число (без-)знаковое. Заранее извиняюсь за глупый вопрос.
Разбираюсь с ассемблером.
Хочется понять, где хранится информация о том, что то или иное число (без-)знаковое. Заранее извиняюсь за глупый вопрос.
Если речь о целых числах, то в самом числе. Старший разряд является знаковым (1 - число отрицательное). См. Дополнительный код. -- @avp
Для целых чисел, на ассемблерном уровне обычно нет информации о том, это число со знаком или без. С битами, составляющими число, можно работать как будто это число со знаком, и как будто это беззнаковое число. Компилятор выбирает подходящие операции основываясь на своей информации. -- @VladD
Компилятор, когда компилирует код, знает, число знаковое или нет. И если он видит "нужно сложить два знаковых числа", то он просто вставит команду "взять данные по одному адресу, загрузить в регистр, взять по другому и записать в регистр и сложить то, что получилось по правилам складывания знаковых чисел". Поэтому ответ на Ваш вопрос - если такая информация нужна, компилятор ее для себя сохраняет (например, в виде отладочной информации или специфического набора команд). В общем случае, смотря в скомпилированный код, нельзя уверенно сказать, какая там была переменная. -- @KoVadim
На ассемблерном уровнем определить, являются ли числа знаковыми, можно по выполняемым над ними операциям. Например, если целые числа умножаются/делятся как знаковые (imul
, idiv
), то по идее они должны быть знаковыми. Точно так же, если используются условные операторы, учитывающие знак (js
, jg
, jge
, jl
, jle
), значит результат последней операции - знаковое число, операнды по идее тоже. Сложение/вычитание для знаковых (считаем, что отрицательные числа хранятся в дополнительном коде) и беззнаковых чисел не различается. -- @insolor
Именно команды условных переходов определяют, проводилась ли операция с знаковыми или беззнаковыми числами. Небольшой пример:
Фрагмент файла c.c:
int a = 10, b = -10;
unsigned ua = a, ub = b;
if (a > b) printf ("%d > %d\n", a, b);
if (ua > ub) printf ("%u > %u\n", ua, ub);
Компиляция в ассемблерный код:
avp@avp-xub11:hashcode$ gcc -S c.c
Результат:
movl $10, 16(%esp) // a = 10
movl $-10, 20(%esp) // b = -10
movl 16(%esp), %eax
movl %eax, 24(%esp) // ua = a
movl 20(%esp), %eax
movl %eax, 28(%esp) // ub = b
movl 16(%esp), %eax
cmpl 20(%esp), %eax // if cmp(a, b)
jle .L2 // a <= b
movl 20(%esp), %eax
movl %eax, 8(%esp)
movl 16(%esp), %eax
movl %eax, 4(%esp)
movl $.LC0, (%esp)
call printf
.L2: movl 24(%esp), %eax
cmpl 28(%esp), %eax // if cmp(ua, ub)
jbe .L3 // ua <= ub
....
Cм. Wikibooks: X86 Assembly/Control Flow -- @avp
Ответ сформирован из комментариев @avp, @VladD, @KoVadim, @insolor под вопросом.