Марк Митчелл - Программирование для Linux. Профессиональный подход
- Название:Программирование для Linux. Профессиональный подход
- Автор:
- Жанр:
- Издательство:Вильямс
- Год:2002
- Город:Москва
- ISBN:5-8459-0243-6
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Марк Митчелл - Программирование для Linux. Профессиональный подход краткое содержание
Данная книга в основном посвящена программированию в среде GNU/Linux. Авторы применяют обучающий подход, последовательно излагая самые важные концепции и методики использования расширенных возможностей системы GNU/Linux в прикладных программах. Читатели научатся писать программы, к интерфейсу которых привыкли пользователи Linux; освоят такие технологии, как многозадачность, многопотоковое программирование, межзадачное взаимодействие и взаимодействие с аппаратными устройствами; смогут улучшить свои программы, сделав их быстрее, надежнее и безопаснее; поймут особенности системы GNU/Linux, ее ограничения, дополнительные возможности и специфические соглашения.
Книга предназначена для программистов, уже знакомых с языком С и имеющих базовый опыт работы в GNU/Linux.
Программирование для Linux. Профессиональный подход - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
#include
#include
/* Имя программы. */
const char* program_name;
/* Вывод информации об использовании программы в поток STREAM
(обычно stdout или stderr) и завершение работы с выдачей кода
EXIT_CODE. Возврат в функцию main() не происходит */
void print_usage(FILE* stream, int exit_code) {
fprintf(stream, "Usage: %s options [ inputfile ... ]\n",
program_name);
fprintf(stream,
" -h --help Display this usage
information.\n"
" -о --output filename Write output to file.\n"
" -v --verbose Print verbose messages.\n");
exit(exit_code);
}
/* Точка входа в основную программу, параметр ARGC содержит размер
списка аргументов; параметр ARGV -- это массив указателей
на аргументы. */
int main(int argc, char* argv[]) (
int next_option;
/* Строка с описанием возможных коротких опций. */
const char* const short_options = "ho:v";
/* Массив с описанием возможных длинных опций. */
const struct option long_options[] = {
{ "help", 0, NULL, 'h' },
{ "output", 1, NULL, 'o' },
{ "verbose", 0, NULL, 'v' },
{ NULL, 0, NULL, 0 } /* Требуется в конце массива. */
};
/* Имя файла, в который записываются результаты работы
программы, или NULL, если вывод направляется в поток
stdout. */
const char* output_filename = NULL;
/* Следует ли выводить развернутые сообщения. */
int verbose = 0;
/* Запоминаем имя программы, которое будет включаться
в сообщения. Оно хранится в элементе argv[0] */
program_name = argv[0];
do {
next_option =
getopt_long(argc, argv, short_options,
long_options, NULL);
switch(next_opt ion) {
case "h": /* -h или --help */
/* Пользователь запросил информацию об использовании
программы, нужно вывести ее в поток stdout и завершить
работу с выдачей кода 0 (нормальное завершение). */
print_usage(stdout, 0);
case 'o': /* -о или --output */
/* Эта опция принимает аргумент -- имя выходного файла. */
output_filename = optarg;
break;
case 'v': /* -v или --verbose */
verbose = 1;
break;
case '?': /* Пользователь ввел неверную опцию. */
/* Записываем информацию об использовании программы в поток
stderr и завершаем работу с выдачей кода 1
(аварийное завершение). */
print_usage(stderr, 1);
case -1: /* Опций больше нет. */
break;
default: /* Какой-то непредвиденный результат. */
abort();
}
}
while (next_option != -1);
/* Обработка опций завершена, переменная OPTIND указывает на
первый аргумент, не являющийся опцией. В демонстрационных
целях отображаем эти аргументы, если задан режим VERBOSE. */
if (verbose) {
int i;
for (i = optind; i < argc; ++i)
printf("Argument: %s\n", argv[i]);
}
/* Далее идет основное тело программы... */
return 0;
}
Может показаться, что использование функции getopt_long()
приводит к написанию громоздкого кода, но, поверьте, самостоятельный синтаксический анализ опций командной строки — гораздо более трудоемкая задача. Функция getopt_long()
достаточно универсальна и гибка в работе с опциями, но лучше не заниматься сложными вещами. Старайтесь придерживаться традиционной структуры задания опций.
2.1.4. Стандартный ввод-вывод
В стандартной библиотеке языка С определены готовые потоки ввода и вывода ( stdin
и stdout
соответственно). Они используются функциями scanf()
, printf()
и целым рядом других библиотечных функций. Согласно идеологии UNIX, стандартные потоки можно перенаправлять. Это позволяет образовывать цепочки программ, связанных посредством каналов (конкретный синтаксис перенаправления потоков и работы с каналами можно узнать в документации к интерпретатору команд).
Есть также стандартный поток ошибок: stderr
. Программы должны направлять предупреждающие сообщения и сообщения об ошибках в него, а не в поток stdout
. Это позволяет отделять обычные выводные данные от разного рода служебных сообщений. К примеру, стандартный поток вывода можно направить в файл, а сообщения об ошибках, по-прежнему отображать на консоли. Запись в поток stderr
осуществляется с помощью функции fprintf()
:
fprintf(stderr, ("Error: ..."));
Все три стандартных потока доступны низкоуровневым функциям ввода-вывода ( read()
, write()
и т.д.) через дескрипторы файлов. В частности, поток stdin
имеет дескриптор 0, stdout
— 1, a stderr
— 2.
При вызове программы иногда требуется одновременно перенаправить потоки вывода и ошибок в файл или канал. Синтаксис подобной операции зависит от используемого интерпретатора команд. В интерпретаторах семейства Bourne shell (включая bash
, который по умолчанию установлен в большинстве дистрибутивов Linux) это делается так:
% program > output_file.txt 2>&1
% program 2>&1 | filter
Запись 2>&1
означает, что файл с дескриптором 2 ( stderr
) объединяется с файле имеющим дескриптор 1 ( stdout
). Обратите внимание на то, что эта запись должна идти после операции перенаправления в файл (первый пример), но перед операцией перенаправления в канал (второй пример).
Поток stdout
является буферизуемым. Записываемые в него данные не посылаются на консоль (или на другое устройство в случае перенаправления), пока буфер не заполнится, программа не завершит работу нормальным способом или файл stdout
не будет закрыт. Осуществить принудительное "выталкивание" буфера позволяет функция fflush()
:
fflush(stdout);
В то же время поток stderr
не буферизуется. Записываемые в него данные сразу попадают на консоль. [6] В C++ аналогичное различие существует между потоками cout и cerr . Манипулятор endl добавляет в конец потока символ новой строки и вызывает "выталкивание" буфера. Если состояние буфера временно менять не нужно (из соображений производительности, например), воспользуйтесь вместо манипулятора константой '\n' .
Указанная особенность потока stdout
может приводить к неожиданным результатам. Например, в следующем цикле точка не выводится каждую секунду. Вместо этого все символы сначала помещаются в буфер, а затем целая их группа одновременно выводится на экран, когда буфер оказывается заполненным.
while (1) {
printf(".");
sleep(1);
}
А в этом цикле происходит то, что нам нужно:
while (1) {
fprintf(stderr, ".");
sleep(1);
}
2.1.5. Коды завершения программы
Когда программа завершает работу, она уведомляет операционную систему о своем состоянии, посылая ей код завершения, который представляет собой 16-разрядное целое число. По существующему соглашению нулевой код свидетельствует об успешном завершении, а ненулевой указывает на наличие ошибки. Некоторые программы возвращают различные ненулевые коды, обозначая разные ситуации.
Читать дальшеИнтервал:
Закладка: