|
Программирование >> Структура ядра и системные вызовы
if.ofT < tmv=m)<time (&time str) ) l.jl ) i-. timv[3] = NULL; cout timv endl; должна напечатать Mon Возвращаемое значение функции clock может варьироваться в зависимости от системы. Стандарт ANSI С определяет, что функция clock возвращает число микросекунд, прощедщих с момента начала выполнения вызывающего ее процесса. Однако в некоторых системах UNIX возвращаемым значением функции clock является количество микросекунд, прошедших с момента первого вызова процессом функции clock. Точное определение возвращаемого результата пользователи могут найти в руководстве программиста или на man-странице, посвященной функции clock, в своей системе. На примере программы clock.C покажем, как правильно использовать функцию clock для контроля времени выполнения процесса независимо от того, как функция реализована в данной системе: finclude <iostream.h> linclude <time.h> main О time t clocktick = CL0CK5 PER SEC; clock t start time = clockO; включить таймер /* выполнить требуемые вычисления...*/ clock t elapsed time = clock() - start time; cout Run time: (elapsed time / clock tick) endl; return 0; 4.7. <assert.h> в заголовке <assert.h> объявляется макрокоманда, используемая для проверки некоторых условий выполнения процесса, которые в нормальной ситуации всегда должны быть истинны. Если все же во время выполнения процесса условие не выполняется, то макрокоманда выводит сообщение об ошибке в стандартный поток ошибок с указанием той строки исходного файла, в которой нарушается проверяемое условие. После этого макрокоманда прерывает процесс. Таким образом, макрокоманда assert помогает сэкономить время, уходящее на отладку программы, проверяя условия типа не должно было произойти . Эта макрокоманда может быть изъята из готового продукта путем указания при компиляции программы ключа -DNDEBUG. В приведенной ниже программе дат. С демонстрируется использование макрокоманды assert: ♦include <fstream.h> ♦include <string.h> ♦include <assert.h> int main( int argc, char* argv[] assert ( argc > 1 ); ifstream ifs( argv[l] ); assert( ifs.good0 ); . должен быть хотя бы 1 аргумент поток должен открываться нормально char ;*nam = new char{strlen(argv[l])+1]; assert( nam ); не должно быть значения NULL return 0; Когда программа assert. С компилируется и выполняется без аргумента, на консоль выводится сообщение: % СС assert.с -о assert; assert Assertion failed: file assert.C , line 5 Макрокоманда assert определена в <assert.h> следующим образом: #ifndef NDEBUG #define assert(ex) ( if (!(ex)) (\ , fprintf(stderr. Assertion failed: file: \ %s\ line %d\n .\. - LINEJ: exit(f);} m .y..i FILE #endif Заметим, что в данном случае assert является макрокомандой и может компилироваться отдельно от программы пользователя путем определения макроса NDEBUG. 4.8. <stdarg.h> в заголовке <stdarg.h> объявляется набор макрокоманд, которые могут быть использованы для определения функций с переменным количеством аргументов. Примерами таких функций в С являются printf и seanf. Данные функции могут быть вызваны с одним или несколькими аргументами, и для нормальной работы вызываемые функции должны обработать все аргументы. Это достигается путем использования макрокоманд, указанных в заголовке <stdarg.h>. в заголовке <stdarg.h> определяются следующие макрокоманды: #define vajstart(ap.parm) (ар) = (char*)(&(parm) + 1) # define va arg(ap,type) ((type*) ((char*) (ар) += sizeof (type))) [-1] define va end(ap) Чтобы использовать перечисленные макрокоманды, функция должна иметь в своем прототипе один четко определенный аргумент. Макрокоманда va start вызывается той или иной функцией для установки аргумента ар так, чтобы он указывал на позицию в динамическом стеке, где находится следующее значение аргумента после рат (который является последним из известных аргументов вызывающей функции). Макрокоманда делает это путем добавления байтового смещения к адресу данных, на которые указывает рагт. Так определяется адрес следующего после рагт значения аргумента функции. Макрокоманда va arg вызывается, когда необходимо извлечь следующее значение аргумента в динамическом стеке. Для того чтобы эта команда сработала, вызывающий процесс должен знать тип данных следующего аргумента в стеке. Макрокоманда vaarg выполняет для каждого вызова два действия: изменяет ар так, чтобы он указывал на позицию в стеке после следующего аргумента, подлежащего возврату в вызывающую функцию; возвращает следующий аргумент в стеке. Для первой установки ар выполняется операция (char*)(ар) += sizeof(type) которая изменяет тип указателя ар на символьный, а затем увеличивает его значение на размер следующего аргумента. Это, по сути дела, смещает ар так, чтобы он указывал на адрес аргумента, следующего за тем, который подлежит выборке. Второе задание выполняется с помощью операции: 4(type*)( (char*)(ар) += sizeof(type)) )[-!] Данная операция вновь изменяет ар так, чтобы он указывал на массив типа type. Индекс -1 обеспечивает возвращение вызывающей функции следующего аргумента в стеке. Принцип действия макрокоманды va arg показан на приведенной ниже схеме; предполагается, что аргумент, который должен быть возвращен, имеет тип double.
((double*)(ap))[-1] Макрокоманда vajend в настоящее время является макроопределением пустой операции. Она задана как парная для макрокоманды vajstart и предназначена для перспективного расширения функциональных возможностей <stdarg.h>. Программа printf.С содержит функцию my printf, которая эмулирует функцию printf. finclude <iostream.h> finclude <stdio.h> finclude <stdarg.h> finclude <string.h> finclude <floatingpoint.h> fdefine SHOW(s) fputs(s,stdout), cnt+=strlen(s) /* моя версия printf */ int my printf ( cot char* format, ...) char *tokp, ifmt[256], *hdr = ifmt, buf[256]; int cnt = 0; va list pa; strcpy(ifmt,format); получить копию введенного текста va start(pa,format); pa - указатель на аргументы в стеке while (tokp=strchr(hdr,%)) ( /* поиск символа % */ *tokp++ = \0; SHOW(hdr); показывает текст до % if (strchr( dfgeisc% ,*tokp)) { /* выполнять, если символ Ч) формата является допустимым */ switch (*tokp) { case d: %i, %d case i: gconvert((double)va arg(pa,int),sizeof(buf),0,buf); break; case s: %s strcpy(buf,va arg(pa,char*)) ; break; case с: %c buf[0] = va arg(pa,char); buf[l] = \0; break; case f: %f gconvert(va arg(pa,double),8,l,buf) break; i v;,; case g : %g gconvert(va arg(pa, double) , 8, 0,buf); break; case %: %% strcpy(buf, % ); break; SHOW(buf); показать извлеченный аргумент else- /* формат задан неверно. Показать символ как он есть */ putchor (*tokp) ; cnt++y -* hdr * tokp.Vf*:!; показать, если он есть, завершающий текст возвратить число напечатанных символов SHOW(hdr); va end(pa); return cnt; int mainO worldV-Й- int cnt = my printf( Hello %% %s %zZZ\n , cout No. char: cnt endl; cnt = printf ( Hello %% %s %zZZ\n , world ); -1 cout No. char.: cnt endl endl; talent = my printf( There are %d days in %c year\n , 365, cout No. char.: cnt endl; cnt = printf( There are %d days in %c yearXn , 365, cout No. char.: cnt endl endl; cnt = my printf( %g x %i = %f\n , 8.8, 8, 8.8*8); cout No. char.: cnt endl; %i = %f\n , 8.8, 8, 8.8*8); cnt endl endl; A) ; A); cnt = printf( %g X cout No. char, return 0; В приведенной программе функция gconvert преобразует значение типа double в формат символьной строки. Эта функция не входит в стандарт ANSI С, но обычно доступна в большинстве систем UNIX. Прототип функции gconvert выглядит следующим образом: char* gconvert ( double dval, int ndigits, int trailing, char* buf ); Аргумент dval в функции gconvert содержит подлежащее преобразованию значение типа double, а аргумент buf указывает на определяемый пользователем буфер, в который помещается преобразованная символьная строка. Аргумент ndigits задает максимальное число значащих цифр, которые может содержать буфер buf а значением аргумента trailing может быть О или 1, что определяет, будет или нет отброшена последняя десятичная точка или 0. Эта функция возвращает адрес буфера, указанный в аргументе buf Компиляция и пробный запуск этой тест-программы дали такие результаты: % СС printf.с -о printf % printf Hello % world zZZ No. of char: 18 Hello % world zZZ No. of char: 18 There are 365 days in A year No. of char: 29 There are 365 days in A year No. of char: 29 8.8 X 8 = 70.400000 No. of char: 20 8.8 X 8 = 70.400000 No. of char: 20 С макросом va arg связаны функции vfprintf vsprintf vprintf Они подобны соответственно функциям fprintf sprintf и printf, за исключением того, что принимают ар как указатель на аргументы вызывающих функций. Прототипы этих функций представлены ниже: int vprintf ( const char* format, va list ap ); int vsprintf ( char* buf, const char* format, vajist ap ); int vfprintf ( FILE* fp, const char* format, vajist ap ); Данные функции могут быть использованы для создания универсальной функции выдачи сообщений: /* source file: test vfprintf.С */ ♦include <stdio.h> ♦include <stdlib.h> ♦include <stdarg.h> typedef enum { INFO, WARN, ERROR, FATAL static int numErr, numWarn, numlnfo; MSG TYPE ENUM; void msg ( const MSG TYPE ENUM mtype, void* format, humlnfoV) switch (mtype) case INFO: break; case WARN: < numWarn++; fputs ( Warning: .stderr ); break; . .i.u case ERROR: , numErr++; fputs( Error: ,stderr ) ; break; case FATAL: , fputs ( Fatal: , stderr ), break; i . , ) . r- va list ap; va start( ap, format ); vfprintf( stderr, (char*)format, ap ); va end( ap ); .Of.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |