Главная · Поиск книг · Поступления книг · Top 40 · Форумы · Ссылки · Читатели

Настройка текста
Перенос строк


    Прохождения игр    
Demon's Souls |#13| Storm King
Demon's Souls |#11| Мaneater part 2
Demon's Souls |#10| Мaneater (part 1)
Demon's Souls |#9| Heart of surprises

Другие игры...


liveinternet.ru: показано число просмотров за 24 часа, посетителей за 24 часа и за сегодня
Rambler's Top100
Образование - Богатырев А. Весь текст 1009.15 Kb

Хрестоматия по программированию на Си в Unix

Предыдущая страница Следующая страница
1 ... 18 19 20 21 22 23 24  25 26 27 28 29 30 31 ... 87
требуется.    Для   файла      было   бы  использовано  макроопределение
_SYS_TYPES_H.

3.20.  Любой макрос можно отменить, написав директиву

        #undef имяМакро

Пример:

    #include 
    #undef M_UNIX
    #undef M_SYSV
    main() {
            putchar('!');
    #undef  putchar
    #define putchar(c) printf( "Буква '%c'\n", c);
            putchar('?');

    #if defined(M_UNIX) || defined(M_SYSV)
    /* или просто #if M_UNIX */
            printf("Это UNIX\n");
    #else
            printf("Это не UNIX\n");
    #endif /* UNIX */
    }

Обычно #undef используется именно для переопределения макроса,  как  putchar  в  этом
примере (дело в том, что putchar - это макрос из ).
     Директива #if, использованная нами,  является  расширением  оператора  #ifdef  и
подставляет текст если выполнено указанное условие:

А. Богатырев, 1992-95                  - 135 -                              Си в UNIX

    #if  defined(MACRO)  /* равно #ifdef(MACRO)  */
    #if !defined(MACRO)  /* равно #ifndef(MACRO) */
    #if VALUE > 15       /* если целая константа
                            #define VALUE 25
                            больше 15 (==, !=, <=, ...) */
    #if COND1 || COND2   /* если верно любое из условий */
    #if COND1 && COND2   /* если верны оба условия      */

Директива #if допускает использование в качестве аргумента довольно  сложных  выраже-
ний, вроде

    #if !defined(M1) && (defined(M2) || defined(M3))

3.21.  Условная компиляция может использоваться для трассировки программ:

    #ifdef DEBUG
    # define DEBUGF(body)   \
    {                       \
            body;           \
    }
    #else
    # define DEBUGF(body)
    #endif

    int f(int x){   return x*x; }
    int main(int ac, char *av[]){
            int x = 21;
            DEBUGF(x = f(x); printf("%s equals to %d\n", "x", x));
            printf("x=%d\n", x);
    }

При компиляции

    cc -DDEBUG file.c

в выходном потоке программы будет присутствовать отладочная выдача.   При  компиляции
без -DDEBUG этой выдачи не будет.

3.22.  В языке C++ (развитие языка Си) слова class, delete,  friend,  new,  operator,
overload,  template,  public, private, protected, this, virtual являются зарезервиро-
ванными (ключевыми).  Это может вызвать небольшую проблему при переносе текста  прог-
раммы на Си в систему программирования C++, например:

    #include 
      ...
    int fd_tty = 2;   /* stderr */
    struct termio old, new;
    ioctl (fd_tty, TCGETA, &old);
    new = old;
    new.c_lflag |= ECHO | ICANON;
    ioctl (fd_tty, TCSETAW, &new);
      ...

Строки, содержащие имя переменной (или функции) new, окажутся  неправильными  в  C++.
Проще всего эта проблема решается переименованием переменной (или функции).  Чтобы не
производить правки во всем тексте, достаточно переопределить имя при помощи директивы
define:

А. Богатырев, 1992-95                  - 136 -                              Си в UNIX

    #define new    new_modes
      ... старый текст ...
    #undef new

При переносе программы на Си в C++ следует также учесть, что в C++ для каждой функции
должен  быть  задан прототип, прежде чем эта функция будет использована (Си позволяет
опускать прототипы для многих функций, особенно возвращающих значения типов  int  или
void).

А. Богатырев, 1992-95                  - 137 -                              Си в UNIX

4.  Работа с файлами.
     Файлы представляют собой области памяти на внешнем носителе (как правило магнит-
ном диске), предназначенные для:
-    хранения данных, превосходящих по объему память компьютера (меньше,  разумеется,
     тоже можно);
-    долговременного хранения информации (она сохраняется при выключении машины).

В UNIX и в MS DOS файлы не имеют  предопределенной  структуры  и  представляют  собой
просто  линейные  массивы  байт.   Если вы хотите задать некоторую структуру хранимой
информации - вы должны позаботиться об этом в своей программе сами.  Файлы отличаются
от обычных массивов тем, что
-    они могут изменять свой размер;
-    обращение к элементам этих массивов производится не при помощи операции индекса-
     ции [], а при помощи специальных системных вызовов и функций;
-    доступ к элементам файла происходит в так  называемой  "позиции  чтения/записи",
     которая  автоматически продвигается при операциях чтения/записи, т.е. файл прос-
     матривается последовательно.  Есть, правда, функции для произвольного  изменения
     этой позиции.

Файлы имеют имена и организованы в иерархическую древовидную структуру из каталогов и
простых  файлов.  Об  этом и о системе именования файлов прочитайте в документации по
UNIX.

4.1.  Для работы с каким-либо файлом наша программа должна открыть этот файл -  уста-
новить  связь  между  именем  файла и некоторой переменной в программе.  При открытии
файла в ядре операционной системы выделяется  "связующая"  структура  file  "открытый
файл", содержащая:
f_offset:
     указатель позиции чтения/записи, который в дальнейшем мы  будем  обозначать  как
     RWptr.  Это  long-число,  равное  расстоянию в байтах от начала файла до позиции
     чтения/записи;
f_flag:
     режимы открытия файла: чтение, запись, чтение и запись, некоторые дополнительные
     флаги;
f_inode:
     расположение файла на диске (в UNIX - в виде ссылки на I-узел файла[*]);
и кое-что еще.
     У каждого процесса имеется таблица открытых им файлов -  это  массив  ссылок  на
упомянутые  "связующие"  структуры[**].   При  открытии  файла  в  этой  таблице  ищется
____________________
   [*] I-узел (I-node, индексный узел) - своеобразный "паспорт", который есть у каждого
файла (в том числе и каталога). В нем содержатся:

      - длина файла                  long   di_size;
      - номер владельца файла        int    di_uid;
      - коды доступа и тип файла     ushort di_mode;
      - время создания и последней модификации
                    time_t di_ctime, di_mtime;
      - начало таблицы блоков файла  char   di_addr[...];
      - количество имен файла        short  di_nlink;
      и.т.п.

Содержимое некоторых полей этого паспорта можно узнать  вызовом  stat().  Все  I-узлы
собраны  в  единую  область в начале файловой системы - так называемый I-файл. Все I-
узлы пронумерованы, начиная с номера 1.  Корневой каталог (файл  с  именем  "/")  как
правило имеет I-узел номер 2.
   [**] У каждого процесса в UNIX также есть свой "паспорт".  Часть этого паспорта нахо-
дится в таблице процессов в ядре ОС, а часть - "приклеена" к самому процессу,  однако
не  доступна  из программы непосредственно.  Эта вторая часть паспорта носит название
"u-area" или структура user. В нее, в частности, входят  таблица  открытых  процессом
файлов

А. Богатырев, 1992-95                  - 138 -                              Си в UNIX

свободная ячейка, в нее заносится ссылка на  структуру  "открытый  файл"  в  ядре,  и
ИНДЕКС  этой  ячейки выдается в вашу программу в виде целого числа -  так называемого
"дескриптора файла".
     При закрытии файла связная структура в ядре уничтожается, ячейка в таблице  счи-
тается свободной, т.е. связь программы и файла разрывается.
     Дескрипторы являются локальными для каждой программы.  Т.е. если  две  программы
открыли  один  и тот же файл - дескрипторы этого файла в каждой из них не обязательно
совпадут (хотя и могут).  Обратно: одинаковые дескрипторы (номера) в разных  програм-
мах  не  обязательно  обозначают один и тот же файл.  Следует учесть и еще одну вещь:
несколько или один процессов могут открыть один и тот же файл одновременно  несколько
раз.   При  этом  будет  создано несколько "связующих" структур (по одной для каждого
открытия); каждая из них будет иметь СВОЙ указатель чтения/записи.  Возможна и ситуа-
ция,  когда несколько дескрипторов ссылаются к одной структуре - смотри ниже описание
вызова dup2.

     fd   u_ofile[]          struct file
      0   ##                 -------------
      1---##---------------->| f_flag    |
      2   ##                 | f_count=3 |
      3---##---------------->| f_inode---------*
     ...  ## *-------------->| f_offset  |     |
    процесс1 |               ------!------     |
             |                     !           V
      0   ## |  struct file        !   struct inode
      1   ## |  -------------      !   -------------
      2---##-*  | f_flag    |      !   | i_count=2 |
      3---##--->| f_count=1 |      !   | i_addr[]----*
     ...  ##    | f_inode----------!-->|    ...    | | адреса
    процесс2    | f_offset  |      !   ------------- | блоков
                -------!-----      *=========*       | файла
                       !                     !       V
            0          !   указатели R/W     !   i_size-1
            @@@@@@@@@@@!@@@@@@@@@@@@@@@@@@@@@!@@@@@@
                           файл на диске

    /* открыть файл */
    int fd = open(char имя_файла[], int как_открыть);
            ...  /* какие-то операции с файлом */
    close(fd);  /* закрыть */

Параметр как_открыть:

    #include 
    O_RDONLY  - только для чтения.
    O_WRONLY  - только для записи.
    O_RDWR    - для чтения и записи.
    O_APPEND  - иногда используется вместе с
    открытием для записи, "добавление" в файл:
        O_WRONLY|O_APPEND, O_RDWR|O_APPEND

Если файл еще не существовал, то его  нельзя  открыть:  open  вернет  значение  (-1),
____________________
     struct file *u_ofile[NOFILE];
ссылка на I-узел текущего каталога
     struct inode *u_cdir;
а также ссылка на часть паспорта в таблице процессов
     struct proc *u_procp;

А. Богатырев, 1992-95                  - 139 -                              Си в UNIX

сигнализирующее об ошибке.  В этом случае файл надо создать:

    int fd = creat(char имя_файла[], int коды_доступа);

Дескриптор fd будет открыт для записи в этот новый пустой файл.   Если  же  файл  уже
существовал,  creat  опустошает его, т.е.  уничтожает его прежнее содержимое и делает
его длину равной 0L байт.  Коды_доступа задают права пользователей на доступ к файлу.
Это число задает битовую шкалу из 9и бит, соответствующих строке

    биты:   876 543 210
            rwx rwx rwx
    r - можно читать файл
    w - можно записывать в файл
    x - можно выполнять программу из этого файла

Первая группа - эта права владельца файла, вторая - членов его группы, третяя -  всех
прочих.  Эти коды для владельца файла имеют еще и мнемонические имена (используемые в
вызове stat):

    #include   /* Там определено: */
    #define S_IREAD           0400
    #define S_IWRITE          0200
    #define S_IEXEC           0100

Подробности - в руководствах по системе UNIX.  Отметим в частности, что open()  может
вернуть   код   ошибки   fd < 0   не  только  в  случае,  когда  файл  не  существует
(errno==ENOENT), но и в случае, когда вам не разрешен соответствующий доступ к  этому
файлу  (errno==EACCES; про переменную кода ошибки errno см. в главе "Взаимодействие с
UNIX").
     Вызов creat - это просто разновидность вызова open в форме

    fd = open( имя_файла,
               O_WRONLY|O_TRUNC|O_CREAT, коды_доступа);

O_TRUNC
     означает, что если файл уже существует, то он должен быть опустошен  при  откры-
     тии. Коды доступа и владелец не изменяются.
O_CREAT
     означает, что файл должен быть создан, если его не было (без этого флага файл не
     создастся,  а open вернет fd < 0).  Этот флаг требует задания третьего аргумента
     коды_доступа[*].  Если файл уже существует - этот флаг не имеет никакого  эффекта,
     но зато вступает в действие O_TRUNC.
     Существует также флаг
O_EXCL
     который может использоваться совместно с O_CREAT.   Он  делает  следующее:  если
     файл  уже  существует,  open  вернет  код  ошибки (errno==EEXIST).  Если файл не
Предыдущая страница Следующая страница
1 ... 18 19 20 21 22 23 24  25 26 27 28 29 30 31 ... 87
Ваша оценка:
Комментарий:
  Подпись:
(Чтобы комментарии всегда подписывались Вашим именем, можете зарегистрироваться в Клубе читателей)
  Сайт:
 

Реклама