В некоторых обстоятельствах использование функций setenv() и clearenv() может привести к утечкам памяти в программе. Как уже говорилось, функция setenv() выделяет буфер памяти, который затем составляет часть среды. Когда вызывается функция clearenv(), она не высвобождает данный буфер (это невозможно, поскольку ей ничего не известно о его существовании). Программа, неоднократно использующая эти две функции, будет постоянно допускать утечку памяти. С практической точки зрения это вряд ли станет проблемой, поскольку обычно программа вызывает clearenv() только один раз в начале своего выполнения, чтобы удалить из среды все записи, унаследованные от своего предка (то есть от программы, вызвавшей exec() для ее запуска).

Функция clearenv() предоставляется во многих реализациях UNIX, но в SUSv3 она не определена. В SUSv3 определено, что, если приложение напрямую изменяет среду, как это делается функцией clearenv(), то поведение функций setenv(), unsetenv() и getenv() становится неопределенным. (Обоснование следующее: если запретить соответствующему приложению непосредствено изменять среду, то реализация ядра сможет полностью контролировать структуры данных, которые применяются ею для создания переменных среды.) Единственный способ очистки среды, разрешенный в SUSv3 приложению, заключается в получении списка всех переменных среды (путем извлечения их имен из environ), с последующим использованием функции unsetenv() для поименного удаления каждой переменной.

Пример программы

Использование всех ранее рассмотренных в этом разделе функций продемонстрировано в листинге 6.4. После начальной очистки среды программа добавляет любые определения среды, предоставленные в виде аргументов командной строки. Затем она добавляет определение для переменной GREET, если таковой еще не имеется в среде, удаляет определение для переменной BYE и, наконец, выводит на экран текущий список переменных среды. Вот как выглядит вывод этой программы:

$ ./modify_env "GREET=Guten Tag" SHELL=/bin/bash BYE=Ciao

GREET=Guten Tag

SHELL=/bin/bash

$ ./modify_env SHELL=/bin/sh BYE=byebye

SHELL=/bin/sh

GREET=Hello world

Если присвоить переменной environ значение NULL (как это делается при вызове clearenv() в листинге 6.4), то мы вправе ожидать, что следующий цикл (в том виде, в котором он используется в программе) даст сбой, поскольку запись *environ будет некорректна:

for (ep = environ; *ep!= NULL; ep++)

puts(*ep);

Но если функции setenv() и putenv() определят, что environ имеет значение NULL, они создадут новый список переменных среды и установят для environ значение, указывающее на этот список. Это приведет к тому, что описанный выше цикл станет работать правильно.

Листинг 6.4. Изменение среды процесса

proc/modify_env.c

#define _GNU_SOURCE /* Для получения различных объявлений из */

#include

#include "tlpi_hdr.h"

extern char **environ;

int

main(int argc, char *argv[])

{

int j;

char **ep;

clearenv(); /* Удаление всей среды */

for (j = 1; j < argc; j++)

if (putenv(argv[j])!= 0)

errExit("putenv: %s", argv[j]);

if (setenv("GREET", "Hello world", 0) == -1)

errExit("setenv");

unsetenv("BYE");

for (ep = environ; *ep!= NULL; ep++)

puts(*ep);

exit(EXIT_SUCCESS);

}

proc/modify_env.c

6.8. Выполнение нелокального перехода: setjmp() и longjmp()

Библиотечные функции setjmp() и longjmp() используются для нелокального перехода. Термин «нелокальный» обозначает, что цель перехода находится где-то за пределами той функции, которая выполняется в данный момент.

Как и многие другие языки программирования, язык C включает в себя инструкцию goto. Злоупотребление ею затрудняет чтение программы и ее сопровождение. Однако временами это весьма полезная инструкция в плане упрощения программы, ускорения ее работы или достижения обоих результатов.

Одно из ограничений имеющейся в языке C инструкции goto заключается в том, что она не позволяет осуществить переход из текущей функции в другую функцию. Но такая функциональная возможность временами может оказаться весьма полезной.

Перейти на страницу:

Похожие книги