Это похоже на ошибку компилятора. Компилятор не может распознать, что значение подписано в случае Integer
(16-битное значение), но соблюдает его в случае Long
.
Кодкоторый выполняет по модулю 4 почти одинаков в каждом случае и следует оптимизированному шаблону для мощностей по модулю 2 :
Long (b Mod 4&
):
or eax, 0xFFFFFFFF # eax = 0xFFFFFFFF (which is -1)
and eax, 0x80000003 # eax = 0x80000003 The modulo op, note it's signed because of the 8
jns other_code # Skip the next three lines if the result is non-negative (it isn't here)
dec eax # eax = 0x80000002
or eax, 0xFFFFFFFC # eax = 0xFFFFFFFE
inc eax # eax = 0xFFFFFFFF (which is -1)
other_code:
В конце eax
содержит 0xFFFFFFFF, который равен -1, который передается для отображения.
Целое число (b Mod 4
):
or eax, 0xFFFFFFFF # eax = 0xFFFFFFFF, ax = 0xFFFF (which is -1 in both cases)
and ax, 0x3 # eax = 0xFFFF0003, ax = 0x0003. Should have been "and ax, 0x8003!"
jns other_code # Skip the next three lines if the result is non-negative (it incorrectly is)
dec ax # Skipped
or ax, 0xFFFC # Skipped
inc ax # Skipped
other_code:
В конце eax
содержит 0xFFFF0003 и затем передается в функцию __vbaStrI2
, которая, очевидно, игнорирует два старших байта и использует только 0003
.
Если вместо and ax, 0x3
был использован and ax, 0x8003
, топропущенные строки сработают и преобразуют 0xFFFF0003
в 0xFFFFFFFF
, что равно -1.
При отключенных оптимизациях поразрядная математика по модулю заменяется простым делением:
sub ax, 0x1 # b = b - 1
mov cx, 0x4 # Prepare division by 4
idiv cx # Integer division
Что касается того, почему случаи для a
и c
работают так, как ожидалось, это потому, что компиляторвычисляет -1 Mod 4
на этапе компиляции и жестко кодирует результат в исполняемом файле:
push 0xFFFFFFFF # Pass hardcoded -1 for display
other_code:
Технически нет ничего, что могло бы помешать ему сделать то же самое в случае b
, потому что это также может доказатьделимое значение составляет -1
. Я не могу точно сказать, почему он этого не сделал - возможно, он остановил статический анализ на один шаг слишком рано, или, может быть, результирующий код для записи -1
обратно в адрес памяти b
был бы менее эффективным в этом отношении. мнение.