|
Программирование >> Структура ядра и системные вызовы
if (mtype == FATAL ) exit ( 2 ) ; /* тест-программа для функции msg */ int mainO msg( INFO, Hello %% %s %%\n , world ); msg( WARN, There are %d days in %c yearXn , 365, A ); msg( ERROR, %g x %i = %f\n , 8.8, 8, 8.8*8 ); msg( FATAL, Bye-bye\n ) ; return 0; Компиляция и выполнение контрольной программы даяи следующие результаты: % СС test vfprintf.с -о test vfprintf % test vfprintf Hello % world % Warning: There are 365 days in A year Error: 8.8 X 8 = 70.400000 Fatal: Bye-bye 4.9. Аргументы командной строки и ключи Функция getopU которая объявляется в заголовке <stdlib.h>, может быть использована для реализации программ, которые принимают UNIX-подоб-ные ключи и аргументы командной строки. Синтаксис вызова таких программ должен быть следующим: <имя программы> [-<ключ> ...] [<аргумент> ...] Все ключи (или опции) должны начинаться с символа - и состоять из одной буквы, например: -о. При этом учитывается и регистр. Несколько ключей можно объединять (так, ключи -а, -Ь можно дать как -аЬ или -Ьа). За ключом может следовать только с ним связанный необязательный аргумент (например, -о a.out). Если два или несколько ключей объединены, то только последний из них может принимать такой аргумент. Например, -о a.out -О может быть записано как -Оо a.out, но не как -оО a.out. Если аргумент не связан с ключом, то после него ключи ставить нельзя. Таким образом, следующий вызов не верен, поскольку перед ключом -о указан не связанный с ним аргумент /usr/prog/test.c. % a.out -1 /usr/prog/test.c -о abc Если при вызове программы указанные правила соблюдаются, то с помощью функции getopt ключи и все связанные с ними аргументы могут быть получены из командной строки. Эта возможность будет показана ниже. Функция getopt и связанные с ней глобальные переменные opterr, optarg и optind объявляются в заголовке <stdlib.h>: extern int optind, opterr; extern char* optarg; int getopt ( int argc, char* const* argv[], const char* optstr; Первыми двумя аргументами функции getopt являются переменные argc и argv функции main. Аргумент optstr содержит список букв ключей, которые допустимы для данной программы. Функция просматривает вектор argv ц ищет ключи, которые определены в optstr. После каждого вызова getopt функция возвращает букву ключа, указанную в optstr и найденную в argv. Если ключ определен в optstr как <switchjetter>:, то этот ключ, если он найден, должен сопровождаться аргументом, который может быть получен через глобальный указатель optarg. Если ключ находится в argv, но не указан в optstr, то функция getopt направит сообщение в стандартный поток ошибок и возвратит символ ? . Если же пользователь перед вызовом getopt устанавливает глобальную переменную opterr в ненулевое значение, то последующие недопустимые ключи, найденные в argv, функция будет игнорировать. Наконец, если в argv больше нет ключей, то функция getopt возвращает значение EOF и переменная optind устанавливается так, чтобы указывать на элемент argv, где хранится первый неключевой аргумент командной строки. Если optind совпадает с argc, то в программе не связанных с ключом аргументов нет. Следующая программа test getopt.C принимает ключи -а, -Ь и -о. Если указан ключ -о, то с ним должно быть задано имя файла: finclude <iostream.h> finclude <stdio.h> finclude <stdlib.h> finclude <string.h> static char* outfile; static int a flag, b flag; int main( int argc, char* argv(] ) { int ch; while ( (ch=getopt( argp, argv, o:ab )) != EOF ) switch ( ch ) { case a: a flag = I,- найден -a break; case b : b flag = l;.b!* найден -b break; case o: outfile = new char[strlen(optarg)+1]; strcpy(outfile,optarg); найдено -о <имя файла> case ?: /* getopt выдаст сообщение об ошибке */. default: break; недопустимый ключ /* ключей больше нет. Просмотреть остальные неключевые аргументы */ for ( ; optind < argc; optind++ ) cout non-s.witch argument: argv[optind] endl; return 0; Компиляция и пробные прогоны программ test getopt. С дали следующие результаты: % СС test getopt.C -о test getopt % test getopt % test getopt -abo xyz /etc/hosts non switch argument: /etc/hosts % test getopt -xay -bz /usr/lib/libc.a test getopt: illegal option - x test getopt: illegal option - у test getopt: illegal option - z non switch argument: /usr/lib/libc.a Фуню1ия getopt сопровождается следующими ограничениями: ключи должны состоять только из одной буквы; ключи должны иметь либо связанные с ними аргументы, либо не иметь их вообще; пользователи не имеют права определять ключи, которые могут иногда принимать, а иногда не принимать аргументы; функция не проверяет тип данных ключей; пользователи не могут указывать взаимоисключающие ключи. Несмотря на указанные недостатки, getopt позволяет значительно сэкономить время, уходящее на разработку и отладку программ, а также обеспечивает соответствие пользовательских программ правилам вызова, принятым в ОС UNIX. 4.10. <setjmp.h> в заголовке <setjmp.h> объявляется набор функций, которые позволяют процессу вызывать оператор перехода goto из одной функции в другую. Вызов С-оператора goto позволяет процессу передать управление выполнением от одного оператора к другому лишь в рамках этой же функции. Функции, определенные в заголовке <setjmp.h>, устраняют данное ограничение. Эти функции необходимо использовать лишь тогда, когда без них действительно нельзя обойтись. Например, если ошибка обнаружена в рекурсивной функции, то есть смысл сообщить об ошибке, а затем выполнить оператор перехода (goto) в основную функцию, то есть как бы начать процесс сначала. Именно это делает shell UNIX при обнаружении ошибки в одном из его процессов. При таких обстоятельствах функции < setjmp.h> обеспечивают эффективное восстановление после сбоев и освобождают пользователя от необходимости добавлять все новые и новые уровни программ контроля ошибок для их исправления. Тем не менее, как и при использовании goto, возникает одна проблема: если эти функции используются в программе нерационально, то пользователю бывает трудно отследить ход выполнения программы. В заголовке <setjmp.h> определяются следующие функции: int setjmp (jmp buf loc ); void longjmp (jmp buf loc, int val ); Функция setjmp регистрирует позицию в коде программы, куда будет возвращать управление будущий оператор go/o (посредством вызова longjmp). Тип данных jmpjbuf определяется в заголовке <setjmp.h>, а в аргументе loc регистрируется позиция оператора setjmp. Если пользователь желает определить в программе несколько точек, в которые может вернуться будущий вызов longjmp, то каждая точка должна быть зарегистрирована в переменной типа jmpjbuf и ее позиция должна быть определена с помощью функции setjmp. Функция setjmp всегда возвращает О, если она вызывается непосредственно в процессе для сохранения состояния стека и регистрации точки возврата. Функция longjmp вызывается для передачи управления в позицию, указанную в аргументе loc. Код программы, отмеченный этой точкой, должен находиться в функции, имеющейся среди функций, которые вызывают текущую функцию. Когда процесс перепрыгивает в эту целевую функцию, все содержимое стека, используемое текущей и вызывающими ее функциями, функцией longjmp отбрасывается. Процесс возобновляет выполнение, повторно выполняя оператор setjmp в целевой функции, которая отмечена аргументом loc. Возвращаемым значением функции setjmp в этом случае является val, указанное в вызове функции longjmp. Значение val не должно быть нулевым (если это О, то функция setjmp устанавливает его в 1), чтобы с его помощью можно было указать, где и почему была вызвана функция longjmp, и выполнить необходимую обработку ошибок. На примере программы test setjmp. С покажем, как могут использоваться функции setjmp и longjmp: I* source file name: test setjmp.C */ ♦include <iostream.h> ♦include <setjmp.h> static jmp buf loc; int mainO int retcode, foo(); if ( (retcode=setjmp( loc )) != 0 ) { устранение ошибок cerr Get here from longjmp. retcode= retcode endl; return /* нормальный ход выполнения программы */ cout Program continue after setting loc via setjmp...\n ; fooO; cout Should never get here ....\n ; return 1; int foo{) { cout Enter foo. Now call longjmp....\n ; longjmp (loc, 5) ; cout Should never gets here....\n ; return 2; Компиляция и пробное выполнение программы testjsetjmp. С дают следующие результаты: % СС test setjump.C -о test setjmp % test setjmp Program continue after setting loc via setjmp... Enter foo. Now call longjmp... Get here from longjmp. return code=5 4.11. pwd.h> в заголовке <pwd.h> определяется набор функций, предназначенных для получения учетной информации о пользователях, содержащейся в UNIX-файле /etc/passwd. Здесь объявляются следующие функции: const struct passwd* getpwnam (const char* user name ); const struct passwd* getpwuid (const int uid ); int setpwent ( void ); const struct passwd* getpwent (void ); int endpwent ( void ); const struct passwd* fgetpwent (FILE* fptr); Тип данных struct passwd определен в <pwd.h> так: struct passwd { char* char* char* char* char* pw name; регистрационное имя пользователя pw passwd; зашифрованный пароль pw uid; /У идентификатор пользователя pw gid; идентификатор группы pw age; информация о минимальном сроке действия пароля pw cqmment; общая информация о пользователе pw dir; начальный каталог пользователя char* pw shell; регистрационный shell пользователя В каждой записи struct passwd содержится одна строка данных файла /etc/password. В этой строке хранится информация о бюджете пользователя в UNIX-системе. В частности, это регистрационное имя пользователя, назначенный идентификатор пользователя, идентификатор фуппы, регистрационный shell, начальный каталог, регистрационный пароль (в зашифрованном виде) и т.д. Функция getpwnam принимает регистрационное имя пользователя в качестве аргумента и возвращает указатель на запись типа struct passwd, которая содержит информацию об этом пользователе, если он имеет право работать в системе. Если заданное имя пользователя недействительно, функция возвращает NULL-указатель. Вывести на экран начальный каталог пользователя с именем joe можно следующим образом: struct passwd *pwd = getpwnam( joe ); if { !pwd ) cerr joe is not a valid user on this system\n ; else cout pwd->pw name ,home= pwd->pw dir endl; Функция getpwuid принимает в качестве аргумента идентификатор пользователя и возвращает указатель на запись типа struct passwd, которая содержит информацию об этом пользователе, если для него в системе создан бюджет. Если заданный идентификатор пользователя недействителен, функция возвращает NULL-указатель. Определить имя и регистрационный shell пользователя с идентификатором 15 можно таким образом: struct passwd *pwd = getpwuid{ 15 ); if ( !pwd ) cerr 15 is not a valid UID on this system\n ; else cout pwd->pw name ,shell= pwd->pw shell endl; Функция setpwent устанавливает указатель чтения на начало файла /etc/passwd. Функция getpwent смещает этот указатель на следующую запись файла /etc/passwd. Когда с помощью функции getpwent будет осуществлен просмотр всех записей файла /etc/passwd, она возвратит NULL-указатель, что обозначает конец файла. Для закрытия файла /etc/passwd вызывается функция endpwent. Следующая профамма, test pwd.C, посылает на стандартный вывод перечень всех определенных в системе пользователей с идентификаторами пользователей и групп: ♦include <iostream.h> ♦include <pwd.h> int main()
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки. |