|
Программирование >> Структура ядра и системные вызовы
функция freopen часто используется для переназначе1я стандартного ввода или стандартного вывода выполняемой программы. Прототип этой функции выглядит следующим образом: FILE* freopen ( const char* file name, const char* mode, FILE* old stream ); Аргумент file name является путевым именем нового потока, который необходимо открыть. Аргумент mode определяет, будет ли новый поток открыт для чтения и (или) записи. Это тот же аргумент, который используется ъ fopen. Новый поток должен быть открыт в режиме, не противоречащем режиму доступа к потоку, на который ссылается аргумент old stream. Например, если старый поток открыт только для чтения, то новый поток необходимо открыть также только для чтения. То же самое касается и ситуации, когда старый поток открыт только для записи или для чтения-записи. Эта функция пытается открыть новый поток с заданным режимом доступа. Если новый поток успешно открыт, старый закрывается и указатель потока old stream теперь обозначает новый поток. Если новый поток не может быть открыт, то old stream все равно закрывается. При успешном выполнении эта функция возвращает значение old stream, а в случае неудачи - значение NULL. В следующем примере эмулируется команда ср (копировать файл) ОС UNIX. Программа принимает в качестве аргументов два путевых имени и копирует содержимое файла, указанного первым аргументом {argvflf), в файл, указанный вторым аргументом {argv[2J). Заметьте, что вместо использования двух указателей потоков для обозначения этих двух файлов указатели стандартных потоков stdin и stdout осуществляют ссылки на исходный и создаваемый файл соответственно через функцию/георея. Данные из исходного файла читаются посредством использования библиотечной функции gets и записываются в создаваемый файл с помощью библиотечной функции puts: #include <stdio.h> int main( int argc, char *argv[}) {.-At.- * nif ( argc !=3 ) { cerr usage: argv[0] <src> <dest>\n ; return 1; 3i t(void) freopen ( argv[l}, x , stdin );...... /* stdin обозначает исходный файл */ -(Void) freopen ( argv[2], w , stdout >W<-;* stdout обозначает результирующий файл */ for ( char buf [256]; gets ( buf ) ; ). puts( buf ) ; return 0; Функция/йорея преобразует дескриптор файла в указатель потока. Дескрипторы файлов используются в интерфейсах прикладного программирования UNIX для получения доступа к файлам. В отличие от указателей потоков они не обеспечивают буферизации данных. Если пользователи хотят выполнить буферизацию данных ввода-вывода, они могут с помощью этой функции преобразовать дескриптор файла в указатель потока. Прототип функции fdopen выглядит следующим образом: FILE* fdopen ( const Int file desc, const char* mode ); Аргумент fdedesc является тем дескриптором файла, который будет преобразован. Аргумент mode задает режим доступа к открываемому потоку. Возможные значения mode такие же, как и в случае вызова fopen, и они должны быть совместимыми с режимом, в котором был открыт файл с дескрипторомУ е йе5с. В частности, если файл открыт только для чтения, то значение mode должно быть У. Точно так же, если данный файл открыт только для записи, то значением шойе должно быть w . В случае успешного выполнения команды эта функция возвращает новый указатель потока, а в случае неудачи - указатель NULL. Одной из причин неудачи может быть несовместимость значения аргумента mode с режимом доступа к файлу с дескриптором fde desc. Следующий пример функции иллюстрирует один из возможных вариантов реализации функции fopen (путем использования fdopen):. FILE* fopen ( const char* file nam, const char* mode ) { int fd, access mode; , r.i>i /* преобразовать mode в целое значение access mode */ ,. it (( fd = open(file name, access mode, 0666 )) < 0 ) return NULL; return fdopen ( fd, mode ); В этом примере аргумент mode необходимо преобразовать из символьной строки в целочисленный флаг accessmode. Далее вызывается API open, который открывает файл, заданный аргументом file name, и возвращаемый дескриптор файла сохраняется в fd. Функция преобразует fd в указатель потока через вызов fdopen и возвращает этот указатель потока. Вызов fdopen используется также в других ситуациях, например при реализации функции рореп. Этот случай будет описан в главе 8. Наконец, в файле заголовков <stdio.h> также объявляются функции рореп и pclose. Данные функции применяются для выполнения в пользовательской программе команд shell Это очень удобный вариант выполнения системных функций в пользовательских программах, причем некоторые из этих функций с помощью стандартных библиотечных функций и системных API не реализуются. Прототипы функций рореп и pclose выглядят следующим образом: FILE* рореп ( const char shell cmd, const char* mode ); int pcloie ( FILE* stream ptr); Аргумент sheU cmd функции рореп - это команда shell, задаваемая пользователем. В качестве аргумента разрешается применять любую команду, которую интерпретатор команд shell может выполнить из командной строки. Пользователи имеют право использовать в команде переназначение ввода, переназначение вывода и конвейеры команд. В ОС UNIX функция рореп для выполнения команды вызывает интерпретатор Bourne-shell. Аргумент mode может иметь значение г или w . Первое из этих значений говорит о том, что функция возвратит указатель потока для чтения данных со стандартного ввода выполняемой команды, а второе - что она возвратит указатель потока для записи данных на стандартный вывод этой команды. Функция возвращает NULL, если команда не может быть выполнена, а в случае успешного ее выполнения - указатель потока. Отметим, что функция рореп создает неименованный канал для передачи данных между вызывающим ее процессом и выполняемой командой. Неименованные каналы рассматриваются в главе 7. Функция pclose вызывается для закрыгия указателя потока, который получен с помощью рореп. Она также гарантирует надлежащее завершение выполняемой команды. Реализация функций рореп и pclose рассматривается в главе 8, где описываются API процессов ОС UNIX. Приведенная ниже программа С выводит на экран все выполняющиеся в UNIX-системе процессы, принадлежащие пользователю root: /* ps.C */ ♦include <stdio.h> int main () ( /* выполнить команду FILE * cmdp = !cmdp ) popen ( -ef I grep root , r ) perror return popen ); char result [256] ; /* теперь прочитать выходную информацию команды grep while ( fgets( result, sizeof(result), cmdp ) ) fputs( result, stdout ); /* отобразить каждую прочитанную строку */ pclose( cmdp ); return 0; закрыть. поток 4.2. <stdlib.h> в заголовке <stdlib.h> объявляется набор функций, служащих для преобразования данных, генерации случайных чисел, полутения и установки переменных среды shell, управления выполнением программ и выполнения команд shell. Обычно эти функции объявляются в заголовке <stdio.h>, но так как они не включают в себя манипулирование потоками, стандарт ANSI С группирует их в отдельный заголовок. Функция system, объявленная в заголовке <stdlib.h>, выполняет операцию подобно функции рореп, за исключением того, что пользователи могут получить доступ к стандартному вводу или выводу выполняемой команды. Прототип функции system выглядит следующим образом: int system ( const char* shell cmd ); Аргумент shell cmd является строкой символов, которая содержит задаваемую пользователем команду shell. Команда должна быть из числа тех, которые интерпретатор shell может выполнить из командной строки. В shell cmd разрешается применять переназначение ввода-вывода и конвейеры команд, в ОС UNIX эта функция для выполнения команды вызывает Bourne-shell. В случае успешного выполнения команда возвращает нулевое значение, а в случае неудачного выполнения - ненулевое значение. Так, команды shell {cd /bin; Is -I sort -b wc > /tmp/wc.out) можно выполнить с помощью следующего оператора: if(system( cd /bin; Is -1 sort -b wc > /tmp/wc.out )==-1) perror( system ); Этот оператор выполняет команды так же, как при вводе их с консоли UNIX. Отметим, что поскольку для выполнения команды shell cmd функция system вызывает новый shell, то произведенные при этом изменение рабочего каталога и установка переменных shell после возврата из системного вызова system оказываются недействительными. Приведенная ниже программа mini-shell. С эмулирует shell UNIX. Она принимает от пользователя одну или более строк команд. И для каждой вводимой строки вызывает функцию system, которая выполняет команду. Программа завершается, когда в стандартном вводе встречается признак конца файла: ♦ include <iostream.h>* ♦ include <stdio.h> ♦include <stdlib.h> int mainO { char cmd[256]; do ( /* показать подсказку shell */ cout *> flush; /* получить пользовательскую команду,*/ /* завершить прием по символу EOF */ if (!cin.getline(cmd,256)) break; /* выполнить пользовательскую команду * if (system(cmd) == -1) perror(cmd); } while (1); /* выйти из mini-shell */ return 0; Перечисленные далее функции определяются в заголовке <stdlib.h> и преобразуют данные из символьных строк в данные других форматов, например double, long, int и т.д.: int atoi ( const char* str val ); double atof ( const char str val ); long ato/ ( const char* str val );* double strtod ( const char* str val, char** endptr); long strto/ ( const char* str val, char** endptr, int radix ); unsigned long strtou/ ( const char* str val, char** endptr, int radix ); Каждая из перечисленных функций преобразует строку, указанную в strjval, в число определенного формата (float, double, long или unsigned long) и возвращает его значение. Если задан аргумент endptr и его значение является адресом указателя символьного типа, то этот указатель устанавливается на ту позицию в строке strval, где завершается ее просмотр. Если преобразование не удается, указатель устанавливается на начало строки str val и функция возвращает нулевое значение. Аргумент radix задает основание системы счисления числовой строки, находящейся в переменной str val. В С и С++ есть соответственно функция sscanf и класс istrstream, которые выполняют операции, аналогичные производимым перечисленными функциями преобразования. Например, функция atol может быть записана оДним из следующих методов: /* метод С */ finclude <stdio.h> long atol (const char* str val) long x; if (sscanf( str val, %ld , &x ) return x; else return 0; /* метод С++ */ finclude <strstream.h> long atol (const char* str val Jf { . long x; istrstream( str val, strlen(str val)+1 ) x; return x; Функции rand и srand, объявленные в заголовке <stdlib.h>, выполняют генерацию случайных чисел. Их прототипы выглядят следующим образом: int rand ( void ); void srand ( unsigned int seed ); Функция srand получает от пользователя число seed и устанавливает начальную точку для новой последовательности псевдослучайных чисел, которые будут возвращаться при каждом следующем вызове rand. Последовательность псевдослучайных чисел, возвращенная функцией rand, может быть повторена, если вызвать функцию srand с тем же значением seed. Если rand вызывается перед srand, то значение seed по умолчанию принимается равным 1. Целые числа, возвращаемые функцией rand, находятся в диапазоне от О до 2 - 1. Если пользователь желает ограничить возвращаемые псевдослучайные числа диапазоном от 1 до Л (где - любое произвольное положительное целое), то вызов rand может быть модифицирован следующим образом: int random num = rand О % N + 1; Следующая функция возвращает случайное число, которое является уникальным для каждого вызова: finclude <time.h> int getrandO { srand( (unsigned)time( 0 ) ); return randO ; В последнем примере функция time объявляется в заголовке <time.h>. Она возвращает целое число, которое обозначает количество секунд, прошедших с 1 января 1970 года до текущего времени. (Более подробно эта функция описана в одном из следующих разделов, где рассматривается заголовок <time.h>.) Так как возвращаемое значение функции time уникально для вызова (предполагается наличие как минимум односекундного интервала между двумя последовательными вызовами), то аргумент seed функции srand также уникален и, следовательно, уникальным является случайное число, возвращаемое функцией rand. Случайные числа широко применяются в программах статистической обработки и анализа.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |