Использование программно-доступных регистров микропроцессора Intel 8086
В языке Си для IBM-совместимых персональных компьютеров обращение к регистрам микропроцессора Intel 8086 осуществляется с помощью специальных объектов, называемых псевдопеременными. Полный список псевдопеременных включает 21 элемент: _АХ, _ВХ, _СХ, _DX, _CS, _DS, _SS, _ES, _SP, _ВР, _DI, _SI, _AL, _AH, _BL, _ВH, _CL, _СН, _DL, _DH, _FLAGS. Их имена образуются из имен регистров с префиксом _ (например, переменная _AX связана с регистром AX). Первые двенадцать псевдопеременных и последняя имеют тип unsigned int, а оставшиеся восемь - unsigned char. Присвоение значения какой-либо переменной, например _АХ, вызывает занесение этого значения в регистр АХ. Получение значения переменной, например _ВХ, эквивалентно получению значения из регистра ВХ.
РАЗДЕЛ 6. ПРИМЕРЫ
Рассмотрим примеры программ, в которых используются различные конструкции языка Си. Первый из них демонстрирует использование управляющих символов n в функциях printf( ) и scanf( ).
/* Пример 1 */ #include <stdio.h> void main(void){ int x, n1, n2; printf("Введите целое число от -32768 до 32767\n"); scanf("%d%n", &x, &n1); printf("x = %d%n\n", x, &n2); printf("n1 = %d, n2 = %d\n", n1, n2);}Результаты работы этой программы имеют вид:
Введите целое число от -32768 до 32767234<Enter>x = 234n1 = 3, n2 = 7Значение n1 определяет число введенных цифр, а n2 - число выведенных символов в строке x = 234 (с пробелами).
Следующий пример показывает использование спецификаций %[], а также символов * и #.
/* Пример 2 */#include <stdio.h> void main(void) { char str_b[21], str_c[21]; /* Последний элемент резервируем под \0 */ int x, n1, n2; float y; printf("Введите строку до 20 символов\n"); scanf("%[Computer]%s", str_b, str_c); printf("str_b = %s, str_c = %s\n", str_b, str_c); y = 12.345678; n1 = 8; n2 = 3; x = 0x100; printf("y = %*.*f\n", n1, n2, y); printf("x(16) = %#x, x(16) = %x, x(10) = %i\n", x, x, x);}Результаты работы программы имеют следующий вид:
Введите строку до 20 символов Comp-1-2-3-4-5<Enter>str_b = Comp, str_c = -1-2-3-4-5у = 12.346 x(16) = 0x100, x(16) = 100, x(10) = 256Здесь пользователем введена строка Comp-1-2-3-4-5. Из нее только четыре символа (Comp) совпадают с первыми символами, заданными в квадратных скобках рассматриваемой спецификации [Computer]. Поэтому только эти четыре символа попадут в первую строку, а оставшиеся символы (1-2-3-4-5) попадут во вторую строку. Число n1 определяет минимальную ширину поля для вывода, а число n2 = 3 - количество цифр после запятой. В результате число 12.345678 будет смещено относительно левой границы, и после запятой будут выведены три цифры. Шестнадцатеричное число 0х100 выведено функцией printf( ) с префиксом 0x, без префикса 0x и в десятичной форме.
Третья программа демонстрирует использование условного оператора if...else и оператора for для организации цикла.
/* Пример 3 */ #include <conio.h>#define SYM 'X' /* Выводимый символ */#define SPACE ' ' /* Определение пробела */#define LF 10 /* Перевод строки */ #define CR 13 /* Возврат каретки */#define LEFT 24 /* Левая граница символа */ #define RIGHT 51 /* Правая граница символа */#define BOTTOM 25 /* Нижняя граница символа */ void main(void) { int col, line; /* col - номер колонки для вывода символа */ /* line - номер линям для вывода символа */ clrscr( ); for (line = 1; line <= BOTTOM; line++) /* Вывод пробелов до левой границы символа */ { for (col = 1; col < LEFT; col++) putch(SPACE); for(col = LEFT + 1; col < RIGHT; col++) /* Вывод символа X на весь экран */ if ((col == (LEFT + line)) || (col == (RIGHT - line))) putch(SYM); else putch(SPACE); putch(LF); /* Возврат каретки и перевод строки после */ putch(CR); /* вывода каждой линии символа */ } getch( ); /* Ожидание нажатия клавиши */}После ее запуска на весь экран будет выведен символ X.
Новая библиотечная функция clrscr( ) имеет следующий прототип:
void clrscr (void);Она выполняет очистку экрана и объявлена в заголовочном файле conio.h.
Четвертая программа демонстрирует использование рекурсивной функции для вычисления факториала. (Отметим, что определение функции factorial( ) может находиться и после функции main( ), но в этом случае функция factorial( ) должна быть объявлена перед функцией main( ), т.е. до main( ) необходимо поместить строку: long factorial(int);.)
/* Пример 4 */ #include <stdio.h> #include <values.h> #include <process.h> long factorial(int value) /* Рекурсивная функция */{ long result = 1; if (value != 0) { result = factorial(value - 1); /* Проверка возможности вычисления факториала */ if (result > MAXLONG / (value + 1)) { fprintf(stderr, "Очень большое число\n"); getch( ); /* Ожидание нажатия клавиши */ exit (1); } result *= value; } return(result);} /* Рекурсивное вычисление факториала числа value */ void main(void) { int value; /* Факториал этого значения вычисляется */ long result; /* Переменная для результата */ puts("Факториал какого числа?"); scanf("%d", &value); result = factorial(value); printf("Результат: %ld\n", result); getch( ); /* Ожидание нажатия клавиши */}Результаты работы этой программы:
Факториал какого числа? 10<Enter>Результат: 362880Пятая программа подсчитывает число символов и слов во вводимых строках (новые символы и слова суммируются с предыдущими; пробелы входят в число введенных символов).
/* Пример 5 */#include <stdio.h> #include <conio.h> #define ESC 27 /* 27 - ASCII-код клавиши ESC */ void CountOfLines(void) {/* Статические переменные будут сохранять старые значения при каждом новом вызове функции CountOfLines */ static int words = 0, symbols = 0; /* words-число слов, symbols-число символов */ char temp, t = 0; /* Временные переменные */ ++symbols; /* Число символов и слов выдается после нажатия клавиши <Enter> */ while ((temp = getche( )) != '\r' ) { ++symbols; /* Подсчитывается каждый символ *//* После одного или нескольких пробелов подсчитывается слово */ if ((temp == ' ') && (t == 1)) continue; if (temp == ' ') { t = 1; ++words; } else t = 0; } if (t == 1) --words; else ++words; printf ("\n Слов: %d; символов: %d\n", words, symbols); }void main(void) { puts("Для завершения программы нажмите <ESC> в начале строки"); puts("Строка не должна начинаться с пробела и с нажатия клавиши" "<Enter>"); puts("Строка не должна завершаться пробелом"); while (getche( ) != ESC) CountOfLines(); putch('\b'); putch(' '); putch('\b');}Результаты работы этой программы:
Для завершения программы нажмите <ESC> в начале строкиСтрока не должна начинаться с пробела и с нажатия клавиши <Enter>Строка не должна завершаться пробеломMouse Keyboard <Enter>Слов: 2 символов: 14<ESC>Следующая группа программ демонстрирует работу с файлами. Она позволяет организовать в файле на диске телефонный справочник и выполняет следующие функции:
- занесение фамилии абонента и номера телефона в справочник;
- поиск в справочнике номера телефона по фамилии абонента;
- удаление из справочника фамилии абонента и номера его телефона.
Ниже приведен текст головной программы main.c:
// Пример 6 //---------------------------------------------------------// Головная программа для работы с телефонным справочником//---------------------------------------------------------#include "A:\my.h" //Заголовочный файл с глобальными //переменными и константами#include "A:\findt.c" //Поиск строки str в файле#include "A:\choicet.c" //Проверка наличия строки в файле#include "A:\addt.c" //Добавление строки в файл#include "A:\subt.c" //Удаление строки из файла void main(int argc, char *argv[ ]){ if (argc == 3) if (*argv[1] == '+') //Добавить запись { if (Choice(argv[2]) == 0) //Нет ли такой //записи в файле? { puts("Эта фамилия есть в справочнике"); exit(1); } Add(argv[2]); //Добавление записи } else if (*argv[1] == '-') Sub(argv[2]); //Удалить запись else puts("Ошибочное значение аргумента"); else if (argc == 2) Find(argv[1]); //Поиск записи else puts("Ошибочное число аргументов");}С помощью директив #include в головную программу включаются файлы: my.h, findt.c, choicet.c, addt.c и subt.c. Считается, что все они находятся в корневом каталоге диска A:. Если это не так, то необходимо изменить соответствующие директивы #include. В файле my.h определены глобальные переменные и некоторые символьные значения.
//Файл заголовков my.h//--------------------------------------------------------//Определения глобальных переменных и символьных значений//--------------------------------------------------------#include <stdio.h>#include <process.h>#include <string.h>#define MAX_NAME 20 //Максимальное число символов в фамилии#define MAX_NUMBER 10 //Максимальное число цифр в телеф. номереchar Name[MAX_NAME]; //Массив фамилийchar Number[MAX_NUMBER]; //Массив для телефонного номераchar File[ ] = "A:\\tel\\tel_num.txt"; //Имя файла справочника int Count; //Число фамилий в справочникеFILE *F_tel; //Логическое имя файла справочникаФайл my.h, в частности, определяет, что телефонный справочник будет организован в каталоге tel диска A:. Поэтому необходимо перед запуском программы main.exe создать этот подкаталог либо использовать другой подкаталог. В последнем случае необходимо изменить строку:
char File[ ] = "A:\\tel\\tel_num.txt";которая задает имя файла с телефонным справочником (tel_num.txt).
Модуль findt.c, текст которого приведен ниже, содержит функцию Find( ) для поиска строки str в файле tel_num.txt.
//Модуль findt.c//----------------------------------------------------------//Функция Find( ) для поиска строки str в файле tel_num.txt//----------------------------------------------------------void Find(char *str){ int i;//Если файл невозможно открыть для чтения, то программа//завершает работу if ((F_tel = fopen(File, "r")) == NULL) { fprintf(stderr, "\"%s\" : невозможно открыть\n", File); exit(1); }//Чтение числа записей (Count) в файле if (fread(&Count, sizeof(int), 1, F_tel) != 1) { fprintf(stderr, "\"%s\" : ошибка чтения\n", File); exit(1); }//В цикле for осуществляется поиск нужной записи for (i = 1; i < Count; i++) { fread(Name, 1, MAX_NAME, F_tel); //Чтение имени fread(Number, 1, MAX_NUMBER, F_tel); //Чтение номера if (ferror(F_tel)) //Проверка отсутствия ошибки { fprintf(stderr, "\"%s\" : ошибка чтения\n'', File); exit(1); } if (strcmp(str, Name) == 0) //Если имя совпадает //с введенным, то фамилия //и найденный номер //выводятся на экран { printf("Фамилия : %s\n", Name); printf("Номер телефона: %s\n", Number); fclose(F_tel); return; } }//Если результат поиска отрицательный, то выводится //следующее сообщение fprintf(stderr,"\"%s\" : запись в файле отсутствует\n", File); fclose(F_tel); return;}Модуль choicet.c содержит функцию Choice( ), позволяющую проверить есть ли заданная строка в файле tel_num.txt.
// Модуль choicet.c//----------------------------------------------------------------------//Функция Choice( ), проверяющая есть ли строка str в файле tel_num.txt//----------------------------------------------------------------------int Choice(char *str) { int i; char temp[MAX_NAME + MAX_NUMBER]; if ((F_tel = fopen(File, "r")) == NULL) return 1; //Строки str нет в файле if (fread(&Count, sizeof(int), 1, F_tel) != 1) { fprintf(stderr, "\"%s\" : ошибка чтения\n", File); exit(1); } for (i = 0; i < Count; i++) { fread(temp, 1, MAX_NAME + MAX_NUMBER, F_tel); if (ferror(F_tel)) { fprintf(stderr, "\"%s\" : ошибка чтения\n", File); exit(1); } if (strcmp(str, temp) == 0) { fclose(F_tel); return 0; //Строка str есть в файле } } fclose(F_tel); return 1; //Строки str нет в файле}Модуль addt.c содержит функцию Add( ), которая добавляет заданную строку в файл tel_num.txt.
//Модуль addt.c //-------------------------------------------------------//Функция Add( ) добавляет строку str в файл tel_num.txt //-------------------------------------------------------void Create(void) //Создает файл, если он не существует{ if ((F_tel = fopen(File, "wb+")) == NULL) { fprintf(stderr, "\%s\" : невозможно открыть\n", File); exit(1); } Count = 0; if ( ! fwrite(&Count, sizeof(Count), 1, F_tel)) { fprintf(stderr, "\"%s\" : ошибка записи\n", File); exit(1); }}void Add(char *s) //Добавляет запись в файл{ char str[MAX_NAME], sn[MAX_NUMBER]; //Временные массивы int i; for (i = 0; i < MAX_NAME; i++) str[i] = ' '; //Пробелы в str strcpy(str, s); //Копирование строки в str if ((F_tel = fopen(File, "rb+")) = = NULL) Create(); //Создаем файл, если он не //существует else if (fread(&Count, sizeof(Count), 1, F_tel) != 1) { fprintf(stderr, "\"%s\" : ошибка чтения\n", File); exit(1); } printf("Номер телефона : "); //Запрашивается и вводится номер if (gets(Number) == NULL || *Number == '\0') { fclose(F_tel); return; //Возврат, если номер не введен }//Установка указателя в файле на первую свободную запись if (fseek(F_tel, (long)((MAX_NAME+MAX_NUMBER)*Count), SEEK_CUR)!=0) { fprintf(stderr, "\"%s\" : ошибка поиска\n", File); exit(1); } fwrite(str, 1, MAX_NAME, F_tel); //Запись в файл фамилии for (i = 0; i < MAX_NUMBER; i++) sn[i] = ' '; //Пробелы в sn[ ] strcpy(sn, Number); //Копирование сроки Number в строку sn fwrite(sn, 1, MAX_NUMBER, F_tel); //Запись в файл номера if (ferror(F_tel)) //Проверка наличия ошибки { fprintf(stderr, "\"%s\" : ошибка записи\n", File); exit(1); }//Установка указателя в файле на первый байт if (fseek(F_tel, 0L, SEEK_SET) != 0) { fprintf(stderr, "\"%s\" : ошибка позиционирования\n", File); exit(1); } ++Count; //Увеличение числа записей на единицу//Запись Count в файл if (fwrite(&Count, sizeof(int), 1,F_tel) != 1) { fprintf(stderr, "\"%s\" : ошибка записи\n", File); exit(1); } fclose(F_tel); return;}Модуль subt.c содержит функцию Sub( ), которая удаляет заданную строку из файла tel_num.txt.
//Модуль subt.c//------------------------------------------------------------//Функция Sub( ) удаляет заданную строку из файла tel_num.txt //------------------------------------------------------------void Sub(char *str){ int i, j; char temp[MAX_NAME + MAX_NUMBER]; //Временный массив if ((F_tel = fopen(File, "r+")) == NULL) { fprintf(stderr, "\"%s\" : невозможно открыть\n", File); exit(1); } if (fread(&Count, sizeof(int), 1, F_tel) != 1) { fprintf(stderr, "\"%s\" : ошибка чтения\n", File); exit(1); }//В цикле осуществляется поиск удаляемой строки в файле for (i = 0; i < Count; i++) { fread(temp, 1, MAX_NAME + MAX_NUMBER, F_tel); if (ferror(F_tel)) { fprintf(stderr, "\"%s\" : ошибка чтения\n", File); exit(1); } if (strcmp(str, temp) == 0) //Если срока найдена { for (j = i; j < Count; j++) //она удаляется { fread(temp, 1, MAX_NAME + MAX_NUMBER, F_tel); fseek(F_tel, (long)(j*(MAX_NAME+MAX_NUMBER)+2L), SEEK_SET); fwrite(temp, 1, MAX_NAME + MAX_NUMBER, F_tel); fseek(F_tel, (long)((j+2)*(MAX_NAME+MAX_NUMBER)+2L), SEEK_SET); if (ferror(F_tel)) { fprintf(stderr, "\"%s\" : ошибка чтения\n", File); exit(1); } } --Count; //При удалении строки декремент Count fseek(F_tel, 0L, SEEK_SET); //Установка указателя//Запись уменьшенного значения Count в файл if (fwrite(&Count, sizeof(Count), 1, F_tel) != 1) { fprintf(stderr, "\"%s\" : ошибка записи\n", File); exit(1); } fclose(F_tel); puts("Запись удалена из файла"); return; } } fprintf(stderr, "\"%s\" : отсутствует в базе данных\n", File); fclose(F_tel);}Ниже приводится возможный сценарий работы с программой main.
main + Петров<Enter>Номер телефона: 77-17-89<Enter>main + Иванов<Enter>Номер телефона: 52-98-02<Enter> main Иванов<Enter>Фамилия: ИвановНомер телефона: 52-98-02 main - Петров<Enter> Запись удалена из файла main Петров<Enter>"tel_num.txt" : запись в файле отсутствуетПоследняя программа showt.c позволяет вывести на экран содержимое телефонного справочника.
//Программа showt.c //-------------------------------------------------//Выводит на экран все записи из файла tel_num.txt //-------------------------------------------------#include "my.h" void Show(void) { int i; //Если файл невозможно открыть для чтения, то завершение работы программы if ((F_tel = fopen(File, "r")) == NULL) { fprintf(stderr, "\"%s\" : невозможно открыть\n",File); exit(1); }//Чтение числа записей (Count) в файле if(fread(&Count, sizeof(int), 1, F_tel) != 1) { fprintf(stderr, "\"%s\" : ошибка чтения\n", File); exit(1); }//В цикле осуществляется вывод всех записей for (i=0; i < Count; i++) { fread(Name, 1, MAX_NAME, F_tel); //Читается имя fread(Number, 1, MAX_NUMBER, F_tel); //Читается номер if (ferror(F_tel)) //Проверяется отсутствие ошибки { fprintf(stderr, "\"%s\" : ошибка чтения\n'', File); exit(1); } printf("Фамилия: %s; номер телефона: %s\n", Name, Number); } fclose(F_tel);}void main(void){ Show( );}ЛИТЕРАТУРА
- Скляров В.А. Программирование на языках Си и Си++.- М.: Высшая школа, 1996.
- Березин Б.И., Березин С.Б. Начальный курс С и С++.- М.: ДИАЛОГ-МИФИ, 1999.
- Керниган Б., Ритчи Д. Язык программирования Си.- М.: Финансы и статистика, 1992.
- Подбельский В.В., Фомин С.С. Программирование на языке Си. Учеб. пособие.- М.: Финансы и статистика, 2000.
- Павловская Т.А. C/C++, Программирование на языке высокого уровня.- СПб.: Питер, 2005.
- Касаткин А.И. Профессиональное программирование на языке Си. Системное программирование.- Минск: Высшая школа, 1993.
- Касаткин А.И. Профессиональное программирование на языке Си. Управление ресурсами.- Минск: Высшая школа, 1993.
- Касаткин А.И., Вальвачев А.Н. Профессиональное программирование на языке Си. От Turbo C к Borland C++.- Минск: Высшая школа, 1995.