Марк Митчелл - Программирование для Linux. Профессиональный подход
- Название:Программирование для Linux. Профессиональный подход
- Автор:
- Жанр:
- Издательство:Вильямс
- Год:2002
- Город:Москва
- ISBN:5-8459-0243-6
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Марк Митчелл - Программирование для Linux. Профессиональный подход краткое содержание
Данная книга в основном посвящена программированию в среде GNU/Linux. Авторы применяют обучающий подход, последовательно излагая самые важные концепции и методики использования расширенных возможностей системы GNU/Linux в прикладных программах. Читатели научатся писать программы, к интерфейсу которых привыкли пользователи Linux; освоят такие технологии, как многозадачность, многопотоковое программирование, межзадачное взаимодействие и взаимодействие с аппаратными устройствами; смогут улучшить свои программы, сделав их быстрее, надежнее и безопаснее; поймут особенности системы GNU/Linux, ее ограничения, дополнительные возможности и специфические соглашения.
Книга предназначена для программистов, уже знакомых с языком С и имеющих базовый опыт работы в GNU/Linux.
Программирование для Linux. Профессиональный подход - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
number pop_stack(Stack* stack) {
number answer;
Stack rest_of_stack;
assert(!empty_stack(*stack));
answer = (*stack)->element_;
rest_of_stack = (*stack)->next_;
free(*stack);
*stack = rest_of_stack;
return answer;
}
/* Добавление числа в начало стека. */
void push_stack(Stack* stack, number n) {
Stack new_stack =
malloc(sizeof(struct StackElement));
new_stack->element_ = n;
new_stack->next_ = *stack;
*stack = new_stack;
}
/* Очистка стека. */
void clear_stack(Stack* stack) {
while(!empty_stack(*stack)) {
number top = pop_stack (stack);
destroy_number(top);
}
}
В листинге А.6 показаны объявления типов данных и функций работы со стеком и унарными числами.
number.c
и stack.c
#ifndef DEFINITIONS_H
#define DEFINITIONS_H 1
/* Представление числа в виде связного списка. */
struct LinkedListNumber {
struct LinkedListNumber* one_less_;
};
typedef struct LinkedListNumber* number;
/* Реализация стека чисел, представленных в виде
связных списков. Значение 0 соответствует
пустому стеку. */
struct StackElement {
number element_;
struct StackElement* next_;
};
typedef struct StackElement* Stack;
/* Операции над стеком. */
Stack create_stack();
int empty_stack(Stack stack);
number pop_stack Stack* stack);
void push_stack(Stack* stack, number n);
void clear_stack(Stack* stack);
/* Операции над числами */
number make_zero();
void destroy_number(number n);
number add(number n1, number n2);
number subtract(number n1, number n2);
number product(number n1, number n2);
number even(number n);
number odd(number n);
number string_to_number(char* char_number);
unsigned number_to_unsigned_int(number n);
#endif /* DEFINITIONS_H */
Приложение Б
Низкоуровневый ввод-вывод
Программисты, пишущие Linux-программы на языке С. имеют в своем распоряжении два набора функций ввода-вывода. Один из них включен в стандартную библиотеку языка С: printf()
, fopen()
и т.д. [41] В стандартной библиотеке языка C++ аналогичным целям служат потоки ввода-вывода .
Мы предполагаем, что читатели уже знакомы с языком С и знают, как использовать эти функции ввода-вывода, поэтому не будем их подробно описывать.
Ядро Linux предоставляет собственные операции ввода-вывода, работающие на более низком уровне. В основном они имеют вид системных вызовов и обеспечивают самый непосредственный доступ к файловой системе. По сути, стандартные библиотечные функции реализованы на их основе. Низкоуровневые вызовы обеспечивают наибольшую эффективность операций ввода-вывода.
Б.1. Чтение и запись данных
Первая функция ввода-вывода, с которой сталкиваются те, кто начинают изучать язык С, называется printf()
. Она форматирует текстовую строку и записывает ее в стандартный выходной поток. Обобщенная ее версия fprintf()
записывает текст в заданный поток. Поток данных представляется в программе указателем типа FILE*
. Чтобы получить этот указатель, необходимо открыть файл с помощью функции fopen()
. По завершении работы с файлом его необходимо закрыть с помощью функции fclose()
. Помимо функции fprintf()
существуют также функции fputc()
, fputs()
и fwrite()
, записывающие данные в поток. Функции fscanf()
, fgetc()
, fgets()
и fread()
читают данные из потока.
В низкоуровневых операциях ввода-вывода участвуют не файловые указатели, а дескрипторы. Дескриптор представляет собой целое число, обозначающее конкретный экземпляр файла, открытого в одном процессе. Файл можно открыть для чтения, записи, а также одновременно для чтения и записи. Файловому дескриптору не обязательно соответствует файл: это может быть другой системный компонент, способный передавать или принимать данные (аппаратное устройство, сокет, противоположный конец канала).
Для работы с описанными ниже низкоуровневыми функциями необходимо включить в программу файлы , , и .
Б.1.1. Открытие файла
Чтобы открыть файл и получить дескриптор для работы с ним, необходимо вызвать функцию open()
. В качестве аргументов она принимает строку с путевым именем файла и флаги, определяющие способ открытия. С помощью функции open()
можно также создать новый файл. Для этого ей нужно передать третий аргумент, определяющий права доступа к файлу.
Если второй аргумент равен O_RDONLY
, файл открывается только для чтения. При попытке записи в такой файл будет выдана ошибка. Точно так же флаг O_WRONLY
объявляет файл доступным только для записи. В случае флага O_RDWR
файл открывается и для чтения. и для записи. Не всякий файл можно открыть в любом из трех режимов. Например, существующие права доступа к файлу могут не позволить конкретному процессу открывать файл для чтения или записи. Файл, находящийся в устройстве, запись в которое невозможна (скажем, компакт-диск), тем более нельзя открыть для записи.
Существуют и другие флаги, определяющие режим открытия файла. Все они могут объединяться с помощью операции побитового ИЛИ. Перечислим наиболее распространенные флаги.
■ O_TRUNC
— приводит к очистке существующего файла. Данные, записываемые в файл, замещают предыдущее содержимое файла.
■ O_APPEND
— приводит к открытию файла в режиме добавления. Данные, записываемые в файл, добавляются в его конец.
■ O_CREAT
— означает создание нового файла. Если указанное имя соответствует несуществующему файлу, он будет создан при условии, что заданный каталог существует и процесс имеет разрешение создавать в нем файлы. Если файл уже существует, он будет открыт. При наличии дополнительного флага O_EXCL
функция open()
откажется открывать существующий файл.
Когда в функции open()
задан флаг O_CREAT
, должен присутствовать третий аргумент, определяющий права доступа к создаваемому файлу. О режиме доступа к файлу и битах режима рассказывалось в разделе 10.3, "Права доступа к файлам".
Программа, представленная в листинге Б.1, создает файл, имя которого задано в командной строке. Функции open()
передается флаг O_EXCL
, поэтому в случае указания существующего файла возникнет ошибка. Владельцу и группе нового файла предоставляются права чтения и записи, остальным пользователям — только право чтения (если для пользователя, которому принадлежит программа, установлено значение umask
, права доступа к файлу могут оказаться более жесткими).
umask
При создании файла с помощью функции open()
некоторые из указываемых битов режима могут отключаться. Это следствие того, что значение umask
не равно нулю. Данное значение определяет биты, которые отнимаются от кода режима всех файлов, создаваемых пользователем. Правило определения режима доступа к файлу таково, значение umask
подвергается инверсии, а затем побитово умножается на заданный код режима. Полученное значение становится новым кодом режима.
Интервал:
Закладка: