Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЯЗЫК СИ_РУКОВОДСТВО ПРОГРАММИСТА.doc
Скачиваний:
12
Добавлен:
18.08.2019
Размер:
438.27 Кб
Скачать

1.5. Средства отладки

При отладке программ, написанных на языке "СИ", может использоваться стандартная техника отладки: отладочная печать, отладчик ODT и др. Кроме того,существует ряд дополнительных функций, часть из которых должна включаться явно, а часть включается автоматически, если при трансляции хотя бы одного модуля (файла) программы был задан ключ '-P' и хотя бы одна функция из такого модуля была вызвана. Более подробную информацию о средствах отладки см. "Руководство программиста. Библиотеки. Средства отладки".

#include <stdio.h>

extern file *$$flow;

$$flow = fopen("trace.out", "w");

/* или

$$flow = stderr;

для вывода трассировки на терминал */

$$flow = null; /* прекращение трассировки */

Модуль трассировки вызывается при входе в каждую функцию из файлов, оттранслированных с ключом '-P'. В модуле выполняется проверка на переполнение стека - выполнение программы прерывается с диагностикой

?io-trace-stack below 600 octal

Eсли указатель стека опустится ниже 0600. кроме того, если требуется, выполняется трассировка: если $$flow указывает на дескриптор файла, то имя вызванной функции, адрес возврата в вызвавшую функцию и значение R5 - указателя локальной среды - выводятся в указанный файл для всех функций, оттранслированных с ключом '-P'. Формат вывода следующий:

fun_name<tab>caller<tab>environment

,где fun_name - имя вызванной функции (в ASCII),

caller - адрес возврата (восьмеричный) в вызвавшую

программу,

environment - указатель (восьмеричный) локальной среды вызванной функции (R5). Информация выводится с добавлением '\n' перед и после каждой строки. При первом вызове модуля трассировки устанавливается модуль "traps" (см. ниже) для собственной диагностики аварийных прерываний программы и включается "профиллер" (см. $$prof() ниже).

traps - перехват и диагностика аварийных синхронных

прерываний модуль traps перехватывает и

диагностирует аварийные синхронные прерывания

программы (по векторам 4, 10, 14, 20, 34, 250).

При прерывании сначала непосредственно на терминал выводится диагностика и дамп регистров, после чего вызывается error(). Диагностики, выдаваемые модулем traps, следующие (указан перевод и, в скобках, восьмеричное значение вектора

прерывания):

?CC-F-Odd or nonexistent address trap

прерывание по отсутствующему или недопустимому адресу (4) ?CC-F-Illegal instruction

прерывание по недопустимой инструкции (10)

?CC-F-BPT trap or C run-time library error

BPT прерывание -- возможно, ошибка использования функций библиотеки языка "СИ" (14)

?CC-F-Illegal IOT

недопустимое IOT прерывание (20)

?CC-F-TRAP trap or FORTRAN error signal

TRAP прерывание -- возможно, сигнал ошибки, выдаваемый функциями, написанными на языке FORTRAN (34)

?CC-F-Memory protect violation

прерывание по нарушению защиты памяти (от диспетчера памяти) (250) модуль traps включается, если программа транслируется с ключом '-P', а так же при использовании эмуляторов EIS и (или) FPU и (или) функций $set4() и $set10().

$$prof();

extern char *$$pfil;

extern int $$prnl;

Неявно вызывается при нормальном или аварийном выходе из программы, в которой были использованы функции, оттранслированные с ключом '-P'. При выполнении функции $$prof() открывается файл, на имя которого указывает $$pfil. По умолчанию имя этого файла "PROFIL.OUT", однако его можно изменить явным присваиванием: например, дря того, чтобы вывести "профиль" на терминал, необходимо выполнить

$$pfil = "tt:";

В этот файл выводится "профиль" выполнения программы -- для всех функций, отттранслированных с ключом '-P', выводится имя функкции и количество ее вызовов во время выполнения программы. Вывод выполнияется по формату "%8s %6u", по умолчанию в каждой строке выводися (через пробел) информация о четырех функциях. Это число можно изменить, выполнив явное присваивание переменной $$prnl. например, при выполнении

$$prnl = 0;

В каждой строке выходного файла будет выведена информация только об одной функции, что удобно для сортировки.

abort();

После закрытия всех каналов ввода/вывода (функцией $$cl16()) аварийно завершает программу по инструкции BPT. При работе с отладчиком ODT управление будет передано отладчику.

$$bpt();

прерывает программу выполнением инструкции BPT. При работе с отладчиком ODT управление будет передано отладчику.

char *message; /* строка сообщения */

msg(message); /* вывести сообщение на терминал */

выводит указанную строку на терминал. msg() не использует функции библиотеки ввода/вывода (вывод осуществляется по .PRINT).

char *

caller();

возвращает указатель на имя (в ASCII) функции, вызвавшей текущую функцию (т.е. на имя функции, вызвавшей функцию, вызвавшую caller()). В случае, если вызвавшая (текущую функцию) функция скомпилирована без указания ключа 'P', возвращается указатель на пустую строку. Если функция caller() вызвана из функции main(), то она возвращает указатель на строку "$$init".

file *outf;

calltr(outf);

выводит в файл "outf" путь вызова (последовательность имен функций, находящихся в цепочке вызова) начиная с функции main(). Путь вызова печатается в следующем виде:

[ main sub1 sub2 ]

последним в пути вызова указано имя функции, вызвавшей calltr(). Если функция, находящаяся в цепочке вызовов, скомпилирована без указания ключа 'P', она будет отображена в пути вызова как <NNNNN>, где "NNNNN" - восьмеричный адрес входа в данную функцию. Если функция, стоящая в цепочке вызовов, не использует стандартные для "СИ" функции сохранения и восстановления регистров (csv$() и cret$()), т.е. написана на MACRO или на AS нестандартным (для "СИ") образом, то если эта функция не изменяет "R5", то она просто не будет видна в пути вызова, в противном случае результаты непредсказуемы (вероятнее всего прерывание программы по недопустимому адресу). функция calltr() вызывается (с stderr в качестве аргумента), если программа, скомпилированная с ключом 'P', завершается аварийно или вызовом функции error().

char *start; /* начало дампа */

char *end; /* конец дампа */

memdmp(start, end); /* вывод дампа */

regdmp(); /* дамп регистров */

memdmp() выводит непосредственно на терминал (по .PRINT) дамп (восмеричное содержимое) области памяти от "start" до "end" (точнее, "start" и "end" округляются до чисел, кратных 0100, "start" вниз, а "end" вверх). Если "start" равен 0, то печатается дамп стека начиная от его положения в момент вызова memdmp() и до его исходного положения (исходное положение берется из 042 ячейки).

regdmp() выводит непосредственно на терминал дамп регистров.

2. БИБЛИОТЕКА МАТЕМАТИЧЕСКИХ ФУНКЦИЙ

Язык "СИ" не является языком, ориентированным на вычислительные задачи, но, как любой язык высокого уровня, имеет пакет для вычисления стандартных математических функций. Все функции (за исключением floor() и ceil()) возвращают результат типа double, агрументами всех функций могут быть величины как типа double, так и float.

В стандартном файле определений <math.h> описаны (как double) функции данного пакета, а также определены (по #define) имена "HUGE" как максимальное вещественное число, представимое на данной машине (чуть больше 1.7e38), и "LOGHUGE" как максимальный порядок (39). Некоторые функции пакета возвращают код ошибки через errno ($$ferr).

double x;

double fabs(x);

абсолютное значение x.

double x;

floor(x);

наибольшее целое, не превосходящее x.

double x;

ceil(x);

наименьшее целое, превосходящее x.

double x, *fp;

double modf(x, *fp);

положительную дробную часть числа "wel" и пишет целую часть по адресу

fp. Функция находится в CXLIB.

double x;

double exp(x);

экспоненциальная функция от x. Если значение функции больше HUGE,

возвращается HUGE и устанавливается ошибка "E_RAN".

double x;

double log(x), log10(x);

логарифм x - натурального и десятичного соответственно. Если аргумент

равен или меньше нуля, то функции возвращают 0 и устанавливают

ошибку "E_DOM".

double x;

double sqrt(x);

квадратный корня из x. ошибка как у log.

double x, y;

double pow(x, y);

x в степени y. Ошибка как exp. Если x меньше нуля и y не целый, или

если x и y равны 0, возвращается 0 и устанавливается ошибка E_DOM.

double x, y;

double hypot(x, y);

эффективно и точно вычисляет sqrt(x*x + y*y) (т.е., например,

гипотенузу треугольника по двум катетам). Контроля переполнения не

производится.

typedef struct

double re; /* веществ. часть */

double im; /* мнимая часть */

complex;

complex z;

double cabs(z);

абсолютное значение комплексного числа (определенного, как показано

выше), т.е. sqrt(re*re+im*im). Использует hypot().

double fi; /* угол в радианах */

double

sin(fi), cos(fi),tan(fi);

синус, косинус, тангенс. Если величина тангенса превосходит HUGE,

возвращается HUGE и устанавливается ошибка E_RAN.

double x;

если аргумент по абсолютной величине больше 1, функции возвращают 0 и

устанавливают ошибку E_DOM. Работают через atan().

double x, y;

double atan(x);

double atan2(y, x);

atan() - арктангенс x. Величина результата лежит в диапазоне

[-PI/2..PI/2].

atan2() - арктангенс y/x. Величина результата лежит в диапазоне

[-PI..PI] благодаря учету квадранта (если считать y и x соотв.

координатами).

sinh, cosh - гиперболические синус и косинус при переполнении они

возвращают HUGE/2 и устанавливают ошибку E_RAN.

double x;

double tanh(x);

при больших (>21.) абсолютных значениях аргумента tanh() == sign.

double x;

int n;

double j0(x), j1(x), jn(n, x);

double y0(x), y1(x), yn(n, x);

j0(), j1(), jn() возвращают значение функций бесселя первого рода

порядков 0, 1 и n. Значения функций определены для всех значений

аргумента, ошибок нет. j0() и j1() используют sin(), cos(),

sqrt().Функция jn() использует j0() и j1().

y0(), y1(), yn() возвращают значение функций бесселя второго рода

порядков 0, 1 и n. Значения функций определены только для

положительных значений аргумента -- если x <= 0, возвращают -HUGE и

устанавливают ошибку E_DOM. y0() I y1() используют log() и соотв.

функции j?().yn() использует y0() и y1().

double wel;

int *eptr;

double frexp(wel, eptr);

возвращает m-мантиссу числа wel (m < 1.)и записывает по адресу eprt

целое p, такое, что wel == m * 2**p. Находится в CXLIB.

double wel;

int p;

double ldexp(wel, p);

возвращает wel * (2**p). Находится в CXLIB.

3. ОПИСАНИЕ ГРАФБИБЛИОТЕКИ CGLIB.OBJ ДЛЯ ДВК-3.

Данная библиотека написана Пудгородским Юрием на почве извращений Яковлева С.С. на макроассемблере (библиотека MGLIB).

Описание составил Яковлев С.С.

Last correction : Date 10/03/90 Time 00:01:48

Для подключения данной библиотеки в СИ требуется иметь в программе следующую строку:

#include <grafic.h>

Тем самым вы подключите файл макроопределений, в котором есть следующие операции:

grafon; /* включение графэкрана */

grafoff; /* выключение графэкрана */

alphaon; /* включение симв.экрана */

alphaoff; /* выключение ---//---- */

Кроме того, у вас появляется глобальная переменная int color; и следующие константы:

XMAX=399

YMAX=285

Она определяет тип рисования всех графических примитивов и принимает следующие значения:

cmlor=black; /* Рисует черным */

color=white; /* Белым */

color=invers; /* Инверсией */

color=readcolor; /* Не рисует вообще, но выполняет все положенные

действия. Используется для получения

информации о действительном цвете точки на

экране */

Заливка всего экрана производится процедурой:

erase(cwet); /* cwet принимает значения white,black,invers */

Вызов процедуры "точка":

plot(x,y); /* рисует точку с координатами 0<x<XMAX,0<y<YMAX

если одна из координат за этими пределами, то

точка не светится*/

color=readcolor; /* функция plot возвращает значение цвета */

color1=plot(x,y);/* ук.точки white или black */

Вызов процедуры "линия": line(x0,y0,x1,y1);

Кроме того, можно вызывать значительно более быстрые: horlin(y,x0,x1);

verlin(x,y0,y1);

Вызов процедуры "рамка" или "ящик" - как вам больше нравится: box(x0,y0,x1,y1,wide);

/* Здесь x0,y0,x1,y1 - координаты двух ее противоположных углов, wide

- ширина рамки (внутрь от указанных координат), причем wide=0 означает заливку всего прямоугольника */

circle(x,y,radius);

/* окружность с центром x,y и радиусом radius */ /* Далее вы видите работу с символами. &x,&y означают адреса

координат левого нижнего угла символа. Координата x после вызова

символа изменяется на его ширину (со знаком кратности по x для

нормальных символов).*/

symsml(&x,&y,codesym);

/* рисует микросимвол с координатами левого нижнего угла в указанных

x,y и в матрице 3*5. Символы,не лезущие в такой формат, рисуются в

5*5. код симв- вола от 0 до 63. Символы см. в файле SYMSML.GPR*/

symbol(&x,&y,codesym,length,hight);

/*символы знакогенератора IBM PC 8*8 с соответствующей кратностью по

вертикали и по горизонтали. Отрицательные значения кратности приводят

к зеркальному отображению символа относительно соответствующей оси.

Нулевое значение хотя бы одной кратности означает рисование микросимволов с теми же параметрами. В ближайшее время будет введена глобальная переменная:*/

extern int angle;

/* она будет указывать направление и/или наклон символов:

0 - стандартное положение, без наклона.

1-7 угол поворота по часовой стрелке на PI/4*angle.*/

4. БИБЛИОТЕКА СИСТЕМНЫХ ФУНКЦИЙ ОС RT11

#include <rtio.h>

char *name; /* имя файла в ASCII */

char *dext; /* расширение по умолчанию */

dblk db; /* блок устройства - 4 слова в RAD50 */ atodbl(name,dext,&db);

Преобразует имя файла в 4 слова RAD50, размещенные в структуре типа dblk. Возвращает 1, если преобразование прошло успешно, и 0, если имя файла недопустимо.

#include <match.h>

char *arg; /* исходное имя файла */

filename *buff; /* структура для разобранного имени */ i=breakout(arg,buff);

разбирает имя файла из arg ("filnam.ext") на "filnam" и "ext", которые помещает в структуру типа filename (описана в match.h). Возвращает "TRUE", если удачно разобрала, и "FALSE", если недопустимое имя.

int sysdat;

char *buff;

good=dattoa(sysdat,buff);

преобразует системную дату в формате RT11 (одно слово, биты 14-10 номер месяца (1-12.), 9-5 день (1-31.), 4-0 год (ЬЬ-72.) ) в символьную строку вида DD-MMM-YY (напр. 06-JAN-85) и заносит эту строку в buff. Возвращает:

1 - все нормально

0 - недопустимая дата

#include <rtio.h>

dblk *db; /* указатель на блок устройства */

char *buff; /* буфер для приема строки */

dbltoa(db,buff);

обратная atodbl

#include <stdio.h>

FILE *iop;

char *name; /* групповое имя файла */

char *mode; /* метод открытия */

iop=fwild(name,mode);

iop=fnext(iop);

связывает структуру *iop с групповым именем файла, заданного в name. Групповое имя должно иметь вид [DEV:]FILNAM.EXT, причем части FILNAM и EXT кроме обычных символов могут содержать спецсимволы "*", "?" и "%".

"*" может заменять любую (даже пустую) подстрочку, но не ".", а "?" ("%" является синонимом для "?") может заменять один непустой символ (но не ".").

mode - метод открытия. Допустим только "r", с атрибутами "u" и "n".

Если октрытие группы файлов прошло успешно, fwild() возвращает указатель на структуру типа FILE, иначе 0 и код ошибки в $$ferr. Даже при удачном открытии возвращенная структура не связана с конкретным файлом (т.е. операции передачи запрещены). Фактическое открытие файла производится по fnext().

fnext() открывает следующий файл, имя которого удовлетворяет групповому имени, закрывая предыдущий, если он был. В этом случае возвращает указатель на ту же структуру. Если больше (или вообще) подходящих файлов нет, то возвращает 0, и $$ferr==0. Если возникла ошибка, то тоже возвращет 0, но при этом $$FERR содержит код ошибки.

Eсли fnext() возвратила 0, то структура *iop освобождена - fclose() не требу- ется. Кроме того, в любой момент можно дать fclose(iop) - для освобождения *iop и прекращения работы с данной группой файлов.

char *name;

char *pattern;

i=match(name,pattern);

сравнивает имя файла (name) в виде FILNAM.EXT с групповым именем файла (pattren). Возвращает "TRUE" (1) если имя файла соответствует групповому имени, и "FALSE" (0), если нет.

char *name;

char *pattern;

i=match1(name,pattern);

сравнивает символьную строку с описателем (pattern). Возвращает TRUE (1) если подходит под описатель, и FALSE (0), если не подходит.

#include <rtio.h>

int *rtdir; /* указатель на структуру

описания текущего состояния */

int devnam; /* имя устройства (в rad50) */ rtdir=diropen(devnam);

nfile nfp; /* структура, через которую

возвращается информация о файлах */ i=dirnext(rtdir,&nfp);

diropen(devnam) открывает каталог устройства прямого доступа формата RT11, резервирует и заполняет структуру описания и возвращает указатель на нее. В случае ошибки возвращает 0 и код ошибки в $$FERR.

dirnext(rtdir,&nfl) возвращает информацию о следующем постоянном файле в каталоге, который (каталог) был открыт по diropen().

rtdir - адрес структуры, возвращенный diropen().

nfl - структура типа nfile (определен в rtio.h):

возвращает:

1 - информация о следующем файле помещена в nfile.

0 - каталог исчерпан или ошибка. См. $$FERR - там код ошибки (0 при успешном окончании)