Регистры E*X
являются 32 битами, а регистры *L
- 8 бит. Аналогично, в Windows тип int
имеет ширину 32 бит, а тип char
- 8 бит. Вы не можете произвольно смешивать эти размеры в рамках одной инструкции.
Таким образом, в первой части кода:
sub cl, numB // Line 5
это неправильно, потому что cl
регистр хранит 8-битное значение, в то время как переменная numB
имеет тип int
, который хранит 32-битное значение , Вы не можете вычесть 32-битное значение из 8-битного значения; оба операнда в команде SUB
должны быть одного размера.
Кроме того, в вашем втором фрагменте кода:
mov cl, ecx // Line 5
вы пытаетесь переместить 32-битное значение в ECX в 8-битном CL регистра. Это не может произойти без какого-либо усечения, поэтому вы должны указать его явно. Инструкция MOV
требует, чтобы оба его операнда имели одинаковый размер.
(MOVZX
и MOVSX
являются очевидными исключениями из этого правила, что типы операндов должны совпадать для одной инструкции. Эти инструкции имеют нулевое расширение или знак-расширение, соответственно, меньшее значение, так что оно может быть сохранено в более крупном,)
Однако в этом случае вы даже не нуждаетесь инструкцию MOV. Помните, что CL - это всего лишь 8 бит полного 32-разрядного регистра ECX. Поэтому установка ECX также неявно устанавливает CL. Если вам нужны только младшие 8 бит, вы можете просто использовать CL в следующей инструкции. Таким образом, ваш код становится:
mov ebx, 01fh ; move constant into 32-bit EBX
movzx edx, BYTE PTR letter ; zero-extended move of 8-bit variable into 32-bit EDX
mov ecx, 3 ; move constant into ECX
sub ecx, DWORD PTR numB ; subtract 32-bit variable from ECX
shr edx, cl ; shift EDX right by the lower 8 bits of ECX
and ebx, edx ; bitwise AND of EDX and EBX, leaving result in EBX
mov BYTE PTR resp, bl ; move lower 8 bits of EBX into 8-bit variable
Для того же размера операнда вопросу согласования рассмотренного выше, я также должен был изменить окончательный MOV
инструкции. Вы не можете переместить значение, хранящееся в 32-битном регистре, непосредственно в 8-битную переменную. Вам придется перемещать либо нижние 8 бит, либо верхние 8 бит, позволяя использовать либо регистры BL
, либо BH
, которые являются 8 битами и поэтому соответствуют размеру resp
. В приведенном выше коде я предположил, что вам нужны только младшие 8 бит, поэтому я использовал BL
.
Также обратите внимание, что я использовал спецификации BYTE PTR
и DWORD PTR
. Это не обязательно необходимо в MASM (или встроенном ассемблере Visual Studio), поскольку он может выводить размеры типов из типов переменных. Тем не менее, я думаю, что это повышает удобочитаемость и, как правило, рекомендуется. DWORD
означает 32 бит; он имеет тот же размер, что и int
, и 32-разрядный регистр (E*X
). WORD
означает 16 бит; он имеет тот же размер, что и short
, и 16-разрядный регистр (*X
). BYTE
означает 8 бит; он имеет тот же размер, что и char
, и 8-битный регистр (*L
или *H
).
Вы посмотрели, что создаст компилятор для этого? – EOF
CL - младший байт ECX. Ваша вторая версия выглядит правильно, если вы удалите бессмысленный 'mov cl, ecx'. Поскольку 'numB' - 32 бита, вы должны использовать его с 32-разрядными регистрами. (Или, может быть, 'sub cl, byte ptr numB', чтобы загружать только младший байт, поскольку SHR маскирует значение сдвига в любом случае.) –