Операционная система UNIX. Руководство программиста

     

Как системные вызовы и библиотечные функции используются в C-программах


Как правильно пользоваться системными вызовами и библиотечными функциями, объясняется в соответствующих статьях Справочника программиста. Чтобы чтение Справочника было наиболее эффективным, необходимо знать типичную структуру его статей. Рассмотрим, например, статью gets(3S).

GETS(3S) GETS(3S)
НАЗВАНИЕ
gets, fgets - чтение цепочки символов из потока
СИНТАКСИС
  #include <stdio.h>

char *gets (s) char *s;

char *fgets (s, n, stream) char *s; int n; FILE *stream;



ОПИСАНИЕ
 

Функция gets читает символы из стандартного потока ввода stdin в область памяти, на которую указывает аргумент s. Чтение производится до тех пор, пока не встретится перевод строки или конец файла. Символ перевода строки отбрасывается, а прочитанная цепочка ограничивается нулевым байтом.

Функция fgets считывает (n-1) символов из потока ввода stream в область памяти, на которую указывает аргумент s. Чтение производится до тех пор, пока не встретится перевод строки (в отличие от gets он не отбрасывается) или конец файла. Прочитанная цепочка символов ограничивается нулевым байтом.

СМ. ТАКЖЕ   ferror(3S), fopen(3S), fread(3S), getc(3S), scanf(3S). ДИАГНОСТИКА   Если первым прочитанным символом окажется признак конца файла, то есть фактически ни одного символа не будет считано, то обе функции возвращают пустой указатель NULL. Если обнаружена ошибка чтения, например, при попытке использовать эти функции для файлов, не открытых на чтение, то также возвращается NULL. В остальных случаях возвращается значение указателя s.

В этом примере в одной статье описываются две связанные функции: gets() и fgets(). Обе функции считывают цепочку символов из потока, но делают это несколько по-разному. В разделе ОПИСАНИЕ объясняется, как действует каждая из них.

Раздел СИНТАКСИС содержит информацию о том, как нужно обращаться к описываемым функциям из программы. Заметим, что в первой строке этого раздела записано:

#include <stdio.h>

Это означает, что программе, использующей функции gets() или fgets(), необходима информация из включаемого файла стандартного ввода/вывода. Обычно оператор #include помещается в начале исходного текста. Ниже будет приведена версия файла <stdio.h>, которую можно просмотреть, чтобы понять, что используется функциями gets() и fgets().


Далее в разделе СИНТАКСИС приводится формальное описание функций. Из формального описания можно узнать:


  • Тип объекта, возвращаемого функцией.


  • В нашем примере, обе функции gets() и fgets(), возвращают указатель на символ.


  • Какой объект или объекты следует передавать функции при вызове.


  • Передаваемые объекты указываются в скобках после имени функции. Например, в нашем примере из формального описания следует, что функции gets() нужно передавать указатель на символ. Более подробная информация о передаваемых объектах приводится в разделе ОПИСАНИЕ.


  • Как эти объекты будут интерпретироваться функцией.

    Описание

    char *s;

    в функции gets() означает, что s будет рассматриваться как указатель на символ. Следует иметь в виду, что в языке C при передаче аргументов имя массива преобразуется в указатель на начало этого массива.


Мы рассмотрели простой пример описания функции gets(). Если Вы хотите проверить себя на более сложном примере, попытайтесь понять значение различных элементов описания функции fgets().

Рассматривая функцию fgets(), мы сталкиваемся еще с одной особенностью языка C. Третий аргумент этой функции - stream - есть файл с ассоциированными с ним буферами, описанный как указатель на производный тип FILE. Где определяется этот тип? Правильно! В файле <stdio.h>.

Завершая обсуждение способов вызова функций, описанных в Справочнике программиста, приведем пример фрагмента программы, в котором вызывается функция gets():

#include <stdio.h>

main () { char sarray [80];

for (;;) { if (gets (sarray) != NULL) { . . . /* Выполнить что-либо с цепочкой символов */ . . . } } }

Можно задать вопрос: "Откуда функция gets() считывает символы?". Ответ: "Со стандартного ввода". Под стандартным вводом обычно понимается то, что вводится с клавиатуры терминала, на котором была набрана команда, запустившая выполнение программы, или вывод другой программы, направленный функции gets(). То, что функция gets() считывает информацию со стандартного ввода, можно узнать из раздела ОПИСАНИЕ в статье Справочника. Действительно, там написано: "Функция gets читает символы из стандартного потока ввода...". Стандартный поток ввода определен в файле <stdio.h>.



Ниже приводится содержимое файла <stdio.h>:

#ifndef _NFILE #define _NFILE 20

#define BUFSIZ 1024

/* Размер буфера при выводе в небуферизованный файл */ #define _SBFSIZ 8

typedef struct { int _cnt; unsigned char *_ptr; unsigned char *_base; char _flag; char _file; } FILE;

/* Флаг _IOLBF означает, что файловый вывод будет буфе- ризоваться построчно. _IONBF, _IOLBF и _IOFBF могут использоваться не только как флаги, но и как значения "типа" для передачи функции setvbuf */ #define _IOFBF 0000 #define _IOREAD 0001 #define _IOWRT 0002 #define _IONBF 0004 #define _IOMYBUF 0010 #define _IOEOF 0020 #define _IOERR 0040 #define _IOLBF 0100 #define _IORW 0200

#ifndef NULL #define NULL 0 #endif #ifndef EOF #define EOF(-1) #endif

#define stdin (&_iob[0]) #define stdout (&_iob[1]) #define stderr (&_iob[2])

#define _bufend(p) _bufendtab[(p)->_file] #define _bufsiz(p) (_bufend(p) - (p)->_base)

#ifndef lint #define getc(p) (--(p)->_cnt < 0 ? _filbuf(p) : \ (int) *(p)->_ptr++) #define putc(x, p) (--(p)->_cnt < 0 ? \ _flsbuf((unsigned char) (x), (p)) : \ (int) (*(p)->_ptr++ = \ (unsigned char) (x))) #define getchar() getc(stdin) #define putchar(x) putc((x), stdout) #define clearerr(p) ((void) ((p)->_flag &= \ ~(_IOERR | _IOEOF))) #define feof(p) ((p)->_flag & _IOEOF) #define ferror(p) ((p)->_flag & _IOERR) #define fileno(p) (p)->_file #endif

extern FILE _iob[_NFILE]; extern FILE *fopen(), *fdopen(), *freopen(), *popen(), *tmpfile(); extern long ftell(); extern void rewind(), setbuf(); extern char *ctermid(), *cuserid(), *fgets(), *gets(), *tempnam(), *tmpnam(); extern int fclose(), fflush(), fread(), fwrite(), fseek(), fgetc(), getw(), pclose(), printf(), fprintf(), sprintf(), vprintf(), vfprintf(), vsprintf(), fputc(), putw(), puts(), fputs(), scanf(), fscanf(), sscanf(), setvbuf(), system(), ungetc(); extern unsigned char *_bufendtab[];

#define L_ctermid 9 #define L_cuserid 9 #define P_tmpdir "/usr/tmp/" #define L_tmpnam (sizeof (P_tmpdir) + 15) #endif




Содержание раздела