Чтение онлайн

ЖАНРЫ

Linux программирование в примерах

Роббинс Арнольд

Шрифт:

184 putenv(optarg); /* Требуется GNU putenv. */

185

186 if (optind !=argc && !strcmp(argv[optind], "-")) /* Пропустить опции */

187 ++optind;

188

189 while (optind < argc && strchr(argv[optind], '=')) /* Установить

переменные окружения * /

190 putenv(argv[optind++]);

191

192 /* Если программа не указана, напечатать переменные окружения и выйти. */

193 if (optind == argc)

194 {

195 while (*environ)

196 puts (*environ++);

197 exit(EXIT_SUCCESS);

198 }

Строки 174–179

переносят существующие переменные в новую копию окружения. В глобальную переменную
environ
помещается указатель на пустой локальный массив. Параметр
envp
поддерживает доступ к первоначальному окружению.

Строки 181–184 удаляют переменные окружения, указанные в опции

– u
. Программа осуществляет это, повторно сканируя командную строку и удаляя перечисленные там имена. Удаление переменных окружения основывается на обсуждавшейся ранее особенности GNU
putenv
: при вызове с одним лишь именем переменной (без указанного значения)
putenv
удаляет ее из окружения.

После опций в командной строке помещаются новые или замещающие переменные окружения. Строки 189–190 продолжают сканирование командной строки, отыскивая установки переменных окружения в виде '

имя=значение
'.

По достижении строки 192, если в командной строке ничего не осталось, предполагается, что

env
печатает новое окружение и выходит из программы. Она это и делает (строки 195–197).

Если остались аргументы, они представляют имя команды, которую нужно вызвать, и аргументы для передачи этой новой команде. Это делается с помощью системного вызова

execvp
(строка 200), который замещает текущую программу новой. (Этот вызов обсуждается в разделе 9.1.4 «Запуск новой программы: семейство
exec
»; пока не беспокойтесь о деталях.) Если этот вызов возвращается в текущую программу, он потерпел неудачу. В таком случае
env
выводит сообщение об ошибке и завершает программу.

200 execvp(argv[optind], &argv[optind]);

201

202 {

203 int exit_status = (errno == ENOENT ? 127 : 126);

204 error(0, errno, "%s", argv[optind]);

205 exit(exit_status);

206 }

207 }

Значения кода завершения

126
и
127
(определяемые в строке 203) соответствуют стандарту POSIX.
127
означает, что программа, которую
execvp
попыталась запустить, не существует. (
ENOENT
означает, что файл не содержит записи в каталоге.)
126
означает, что файл существует, но была какая-то другая ошибка.

2.5. Резюме

• Программы на С получают аргументы своей командной строки через параметры

argc
и
argv
. Функция
getopt
предоставляет стандартный способ для последовательного разбора опций и их аргументов GNU версия
getopt
предоставляет некоторые расширения, a
getopt_long
и
getopt_long_only
дает возможность легкого разбора длинных опций.

• Окружение представляет собой набор пар '

имя=значение
', который каждая программа наследует от своего родителя. Программы могут по прихоти своего автора использовать для изменения своего поведения переменные окружения, в дополнение к любым аргументам командной строки. Для получения значений переменных окружения, изменения их значений или удаления существуют стандартные процедуры (
getenv
,
setenv
,
putenv
и
unsetenv
). При необходимости можно получить доступ ко всему окружению через внешнюю переменную
environ
или через третий аргумент
char **envp
функции
main
. Последний способ не рекомендуется.

Упражнения

1. Предположим, что программа принимает опции

– a
,
– b
и
– с
, и что
– b
требует наличия аргумента. Напишите для этой программы код ручного разбора аргументов без использования
getopt
или
getopt_long
. Для завершения обработки опций принимается
– -
. Убедитесь, что -ас работает, также, как
– bYANKEES
,
– b YANKEES
и
– abYANKEES
. Протестируйте программу.

2. Реализуйте

getopt
. Для первой версии вы можете не беспокоиться насчет случая '
optstring[0] == ':'
'. Можете также игнорировать
opterr
.

3. Добавьте код для '

optstring[0] == ':'
' и
opterr
к своей версии
getopt
.

4. Распечатайте и прочтите файлы GNU

getopt.h
,
getopt.с
и
getopt1.с
.

5. Напишите программу, которая объявляет как

environ
, так и
envp
, и сравните их значения.

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

getopt
и
getopt_long
, такими, как:

 • библиотека анализа аргументов Plan 9 From Bell Labs arg(2) [31] ,

 • Argp [32] ,

 • Argv [33] ,

31

http://plan9.bell-labs.com/magic/man2html/2/arg
Примеч. автора.

32

http://www.gnu.org/manual/glibc/html_node/Argp.html
Примеч. автора.

33

http://256.com/sources/argv
Примеч. автора.

 • Autoopts [34] ,

 • GNU Gengetopt [35] ,

 • Opt [36] ,

 • Popt [37] . См. также справочную страницу popt(3) системы GNU/Linux.

7. Дополнительный балл, почему компилятор С не может полностью игнорировать ключевое слово register? Подсказка: какие действия невозможно совершать с регистровой переменной?

34

http://autogen.sourceforge.net/autoopts.html
Примеч. автора.

35

ftp://ftp.gnu.org/gnu/gengetopt/
Примеч. автора.

36

http://nis-www.lanl.gov/~jt/Software/opt/opt-3.19.tar.gz
Примеч. автора.

37

http://freshmeat.net/projects/popt/?topic_id=809
Примеч. автора.

Глава 3

Управление памятью на уровне пользователя

Без памяти для хранения данных программа не может выполнить никакую работу (Или, скорее, невозможно выполнить никакую полезную работу.) Реальные программы не могут позволить себе полагаться на буферы и массивы структур данных фиксированного размера. Они должны быть способны обрабатывать вводимые данные различных размеров, от незначительных до больших. Это, в свою очередь, ведет к использованию динамически выделяемой памяти — памяти, выделяемой в ходе исполнения, а не при компиляции. Вот как вводится в действие принцип GNU «никаких произвольных ограничений».

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

3.1. Адресное пространство Linux/Unix

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

Поделиться с друзьями: