Программирование для Linux. Профессиональный подход - [10]

Шрифт
Интервал

> 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]

Указанная особенность потока >stdout может приводить к неожиданным результатам. Например, в следующем цикле точка не выводится каждую секунду. Вместо этого все символы сначала помещаются в буфер, а затем целая их группа одновременно выводится на экран, когда буфер оказывается заполненным.

>while (1) {

> printf(".");

> sleep(1);

>}

А в этом цикле происходит то, что нам нужно:

>while (1) {

> fprintf(stderr, ".");

> sleep(1);

>}

2.1.5. Коды завершения программы

Когда программа завершает работу, она уведомляет операционную систему о своем состоянии, посылая ей код завершения, который представляет собой 16-разрядное целое число. По существующему соглашению нулевой код свидетельствует об успешном завершении, а ненулевой указывает на наличие ошибки. Некоторые программы возвращают различные ненулевые коды, обозначая разные ситуации.


Рекомендуем почитать
Геймдизайн. Рецепты успеха лучших компьютерных игр от Super Mario и Doom до Assassin’s Creed и дальше

Что такое ГЕЙМДИЗАЙН? Это не код, графика или звук. Это не создание персонажей или раскрашивание игрового поля. Геймдизайн – это симулятор мечты, набор правил, благодаря которым игра оживает. Как создать игру, которую полюбят, от которой не смогут оторваться? Знаменитый геймдизайнер Тайнан Сильвестр на примере кейсов из самых популярных игр рассказывает как объединить эмоции и впечатления, игровую механику и мотивацию игроков. Познакомитесь с принципами дизайна, которыми пользуются ведущие студии мира! Создайте игровую механику, вызывающую эмоции и обеспечивающую разнообразие.


Программирование приложений для мобильных устройств под управлением Android. Часть 1

Книга посвящена разработке программ для мобильных устройств под управлением операционной системы Android. Рассматривается создание приложений с использованием системных компонентов и служб Android. Приведены базовые данные о структуре приложений, об основных классах и их методах, сопровождаемые примерами кода. Часть 1 содержит шесть глав, описывающих основные принципы создания приложений, пользовательский интерфейс, полномочия приложений, а так же базовые классы: Activity, Intent, Fragment. Книга предназначена для программистов, владеющих языком программирования Java и желающих освоить написание приложений, работающих под ОС Android.


Pro Git

Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.



Симуляция частичной специализации

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Питон — модули, пакеты, классы, экземпляры

Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.