Программирование >>  Структура ядра и системные вызовы 

1 ... 14 15 16 [ 17 ] 18 19 20 ... 98


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)+=sizeof (double)

stack

double

char

char

array

of 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.



1 ... 14 15 16 [ 17 ] 18 19 20 ... 98

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика