Безопасно ли использовать getenv () в статических инициализаторах, то есть до main ()? - PullRequest
12 голосов
/ 13 января 2009

Я посмотрел в Стивенс и в Руководстве программиста Posix , и лучшее, что я могу найти, это

Массив строк, называемый enviroment , становится доступным, когда начинается процесс. На этот массив указывает внешняя переменная environ, которая определяется как:

extern char **environ;

Это та переменная окружающая среда , которая заставляет меня колебаться. Я хочу сказать

- Вызывающий процесс / оболочка уже выделил блок строк с нулевым символом в конце

- переменная 'external' environ используется в качестве точки входа для getenv () .

- ipso facto не стесняйтесь вызывать getenv () в статическом инициализаторе.

Но я не могу найти никаких гарантий, что «статическая инициализация» environment предшествует всему другому статическому коду инициализации. Я обдумываю это?

Обновление

На моей платформе (AMD Opteron, Redhat 4, GCC 3.2.3), настройка LD_DEBUG показывает, что environment устанавливается до мои статические инициализаторы называются. Это приятно знать; спасибо, @codelogic. Но это не обязательно результат, который я получу на всех платформах.

Кроме того, хотя я интуитивно согласен с @ChrisW относительно поведения библиотеки времени выполнения C / C ++, это всего лишь моя интуиция, основанная на опыте. Таким образом, любой, кто может получить цитату из какого-нибудь авторитетного источника, гарантирующего, что environment есть до вызова статических инициализаторов, бонусные баллы!

Ответы [ 3 ]

8 голосов
/ 13 января 2009

Я думаю, что вы можете запустить вашу программу с установленным LD_DEBUG, чтобы увидеть точный порядок:

LD_DEBUG=all <myprogram>

EDIT: Если вы посмотрите на исходный код компоновщика времени выполнения (glibc 2.7), особенно в файлах:

  • sysdeps / Unix / SysV / Linux / INIT-first.c
  • sysdeps / i386 / INIT-first.c
  • CSU / Libc-start.c
  • sysdeps / i386 / эльфа / start.S

вы увидите, что argc, argv и environment (псевдоним для __ environment) устанавливаются до вызова каких-либо глобальных конструкторов (функций init). Вы можете следить за выполнением, начиная прямо с _start, фактической точки входа (start.S). Как вы процитировали Стивенса «Массив строк, называемых средой, становится доступным, когда процесс начинается» , предполагая, что назначение среды происходит в самом начале инициализации процесса. Это, подкрепленное кодом компоновщика, который делает то же самое, должно дать вам достаточное спокойствие: -)

РЕДАКТИРОВАТЬ 2: Также стоит упомянуть, что окружение настроено достаточно рано, чтобы даже компоновщик времени выполнения мог запросить его, чтобы определить, следует ли выводить многословно (LD_DEBUG).

4 голосов
/ 13 января 2009

Учитывая, что как настройка среды, так и вызов статических инициализаторов являются функциями, которые должна выполнять среда выполнения языка до вызова main (), я не уверен, что вы найдете здесь гарантию , То есть, я не знаю конкретного требования, чтобы этот имел для работы и чтобы порядок гарантировался до main (), скажем, в спецификациях языка и библиотек ANSI или чего-либо еще ... но я тоже не проверял.

В то же время я не знаю конкретного требования, ограничивающего, какие функции библиотеки времени выполнения могут вызываться из статического инициализатора. И, что более важно, было бы похоже на ошибку времени выполнения (для меня), если бы вы не могли получить доступ к среде из одного.

Исходя из этого, я голосую за то, что ожидал, что это сработает, это безопасное предположение, и текущие данные, кажется, подтверждают эту линию рассуждений.

1 голос
/ 13 января 2009

По моему опыту, библиотека времени выполнения C инициализируется до того, как среда выполнения вызывает инициализаторы ваших статических переменных (поэтому ваши инициализаторы могут вызывать функции библиотеки времени выполнения C).

...