Можно ли использовать getenv() в статических инициализаторах, то есть перед main()?

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

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

extern char **environ;

Это переменная среды, которая меня мешает. Я хочу сказать

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

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

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

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

Update

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

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

Ответ 1

Я думаю, вы можете запустить свою программу с помощью набора 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 и environ (псевдоним для __ environ) задаются перед вызовом глобальных конструкторов (функции init). Вы можете следить за выполнением, начиная прямо с _start, фактической точки входа (start.S). Как вы процитировали Stevens "Массив строк, называемых средой, становится доступным при запуске процесса", предполагая, что назначение среды происходит в самом начале инициализации процесса. Это подкрепляется кодом компоновщика, который делает то же самое, должно дать вам достаточное душевное спокойствие: -)

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

Ответ 2

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

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

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

Ответ 3

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