kibernetics писал(а):в недрах машинных кодов в первом случае будет 2 вызова
В недрах машинных кодов будет одна инструкция
CMP, которая выставляет флаги в регистре EFLAGS. Выставляет флаги — значит меняет значение некоторых битов на определённые (1 или 0).
В целях «экономии транзисторов» отдельная схема сравнения чисел никогда не делалась — инструкция
CMP делает то же самое, что и вычитающая инструкция
SUB, за исключением того, что результат вычитания одного числа из другого просто вычисляется, но никуда не сохраняется.
Поэтому, чем говорить отдельно о сравнивающей инструкции
CMP, правильнее говорить о вычитающей инструкции
SUB.
Если в результате вычитания получился ноль, в регистре EFLAGS устанавливается Z-флаг (Zero-flag).
Если в результате вычитания получилось число, у которого самый старший бит (который у знаковых чисел отвечает за представление отрицательных чисел) равен единицы, в регистре EFLAGS устанавливается S-флаг (Signed-flag).
Есть ряд других флаговых битов (OF, CF), которые устанавливаются в зависимости от того, были ли соблюдены во время операции вычитания определённые условия.
А дальше есть инструкции ветвление, а, проще говоря, условные переходы, которые делают или не делают джамп в зависимости от того, каковы значения флагов.
Например, инструкция JZ (Jump if zero) делает джамп, если Z-флаг (ZF) установлен, то есть если последняя арифметическая операция дала в результате ноль.
Инструкция JNZ делает (Jump if not zero) делает джамп, если Z-флаг сброшен (равен 0).
JE (jump if equal) и JNE (jump if not equal) — делают джамп, если в результате сравнения (CMP) числа были равны ли не равны. Но это не отдельные инструкции, а всего лишь альтерантивные имена для JZ и JNZ, потому что сравнение (CMP) делает под капотом то же, что вычитание (SUB), просто не сохраняет результат. И если числа были равны, то Z-флаг окажется установленным (потому что разность окажется нулевой), и тогда JE сделает джамп, а JNE не сделает, и наоборот.
Инструкции JG и JL делают джамп, исходя из того, было ли первое число больше второго при сравнении, при условии интерпретации этих чисел как знаковых. А на деле они совершает или не совершают флаг исходя их состояния S-флага.
И в целом, все инструкции условных переходов проверяют флаги (не вдаваясь в подробности, какая именно инструкция привела к их изменению — была ли это инструкция сравнения, инструкция вычитания или, может быть, сложения).
С другой стороны, инструкция сравнения (CMP) как и арифметические инстуркции, просто делают некую арифметику над парами чисел, и выставляет или сбрасывает соответственно этому флаги в регистре флагов. Как потом будут использованы эти флаги и какие инструкции ветвления будут применены для их проверки — в эти подробности они не вдаются.
Так что, к примеру, если в языках высокого уровня чтобы разграничить три сценария:
нам придётся дважды сравнивать пару чисел A и B:
If A < B Then Scenario1 ElseIf A > B Then Scenario3 Else Scenario2То на уровне инструкций процессора достаточно один раз произвести сравнения (все необходимые для дальнейших условных переходов флаги будут установлены сразу), а потом с помощью инструкций условного перехода перейти к обработке нужного сценария:
- Код: Выделить всё
CMP EAX, EBX
JG Scenario1
JL Scenario2
Scenario3 тут
То есть инструкция CMP сравнивает пару чисел сразу по всем критериям разом: отдельный бит в регистре флагов будет показывать, были ли числа равны, другой бит будет показывать, было ли одно число больше другого при их интерпретации как знаковые числа, другой бит будет показывать, было ли одно число больше другого при их интерпретации как беззнаковые. А инструкции ветвеления (условных переходов) уже проверяют эти биты, не трогая сами числа.
Всё это относится к целым числам и 32-битной архитектуре x86. Для x86-64 ситуция аналогичная за исключением того, что регистры называются чуть иначе. Для чисел с плавающей точкой есть свои особенности (сравнение делается другой инструкцией, результат сравнения заносится не в EFLAGS, в флаговый регистр FPU). Для других архитектур всё может быть совсем по другому — их много, и нужно о каждой говорить отдельно.