Немного теории
Я получил много писем с таким вопросом:
TASM выдает ошибку: Near jump or call to different CS.
Я предложил вставить строку assume cs:CSEG. Что же происходит?
Дело в том, что эта строка указывает Ассемблеру на привязку сегментного регистра CS к нашему сегменту (CSEG). MASM ассемблирует прекрасно и без этой строки. Если оператор assume отсутствует, то MASM как бы по умолчанию вставляет ее автоматически.
Другое дело TASM. Он, встретив в программе строки вида:
loop Label_1 jmp Label_2 call Procedure
не может "понять" к какому сегменту следует обратиться (CS, DS, ES) и выдает сообщение об ошибке.
Как уже говорилось, мы пишем com-файлы в которых всего один сегмент (мы обзываем его CSEG). Если вы создадите еще один (например, DSEG), то компоновщик (link.exe), при попытке создать com-файл, выдаст ошибку.
Чтобы полностью закрыть данную тему, привожу полный вид разбираемой нами строки:
assume cs:CSEG, ds:CSEG, es:CSEG, ss:CSEG
Этим мы указываем Ассемблеру на то, что сегментные регистры CS, DS, ES, SS будут указывать на наш единственный сегмент.
Допустим, в текущем каталоге файла "file" не было найдено. Тогда, функция 3Dh устанавливает в единицу флаг переноса (помните схожую ситуацию с флагом нуля из прошлых глав?). Если же файл все-таки найден и успешно открыт, то флаг переноса устанавливается в нуль.
Для проверки состояния флага переноса используется оператор JC (Jump if Carry - переход, если установлен флаг переноса) и JNC (Jump if Not Carry - переход, если флаг переноса не установлен): ... int 21h jc Error Ok: .... Error: ...
или так: ... int 21h jnc Ok Error: ... Ok: ...
Естественно, вместо меток Ok и Error (ошибка) можно задавать любые другие имена.
Вы уже можете сделать вывод, что JC и JNC - команды условного перехода.
Все функции устанавливают в единицу флаг переноса, если произошла ошибка и сбрасывают его, если ошибки не было.
Вот полный пример открытия файла: ... mov ax,3D00h mov dx,offset File_name int 21h jc Bad_file mov dx,offset Mess1 Quit_prog: mov ah,9 int 21h int 20h Bad_file: mov dx,offset Mess2 jmp Quit_prog
Далее. При успешном открытии файла в AX возвращается уникальный идентификационный номер файла. В дальнейшем, при обращении к данному файлу, будет указываться не его имя, а этот номер. После вызова функции 3Dh сохраните номер файла!
После того, как мы закончили работу с файлом (записали или прочитали что-нибудь), его необходимо закрыть функцией 3Eh :
Функция 3Eh прерывания 21h - закрытие файла:
Вход: | AH = 3Eh |
Не забывайте закрывать файл! mov ah,3Eh mov bx,Handle int 21h
Файл закрыт.
Обратите внимание на запись mov bx,Handle. Здесь Handle - это переменная, в которую необходимо будет занести номер файла после открытия. Переменные мы подробно рассмотрим в следующих выпусках, а сейчас коснемся только того, как создать переменную Handle. Вот пример: Handle dw 0
Здесь мы резервируем два байта для хранения каких-нибудь данных. В данном случае - для хранения номера файла. Таким образом, рассмотрим фрагмент программы, которая открывает файл для чтения, сохраняет номер файла в переменную, а затем закрывает файл: ... mov ax,3D00h mov dx,offset File_name int 21h jc Error mov Handle,ax ; файл открыт успешно... mov ah,3Eh mov bx, Handle int 21h ;файл закрыт Error: int 20h ... Handle dw 0 ...
Для чтения информации из файла используется функция 3Fh, а для записи в файл - 40h. При этом BX должен содержать тот самый номер файла (Handle), CX - количество читаемых или записываемых байт, DS:DX - адрес буфера для чтения / записи.