Хорошо, я понял это сейчас, после своего собственного эксперимента.
Поскольку передача массива, начинающегося с NULL
(0
), в execv
приводит к распечатке программы LC_MEASUREMENT=de_DE.UTF-8
, я понял, что это должно означать, что argv[3]
относится к элементу в процессе environment (LC_MEASUREMENT - одна из переменных среды, используемая для настройки параметров локали в Linux).
Решение с execv
Поскольку execv
скопирует текущую среду в новую программу, нам просто нужно изменить среду и поместить строку "Hello World!"
в правильное место передзвонит execv
.Оказывается, что строка, которая печатается, является той, на которую указывает индекс 2 среды.
Чтобы получить доступ к текущей среде, нам нужно объявить переменную environ
вне main
:
external char **environ;
int main()
{
...
, а затем сделать это перед вызовом execv
:
char *argv[] = { NULL };
environ[2] = "Hello world!";
execv("filepath", argv);
Более простое решение с execve
Вместо объявления external char **environ
и изменения текущей среды перед вызовом execv
, мы можем использовать функцию execve
, которая позволяет нам передавать новуюмассив строк для использования в качестве среды для программы:
char *argv[] = { NULL };
char *envp[] = { "foo", "bar", "Hello World!", NULL };
execve("filepath", argv, envp);
Как показывает приведенный выше фрагмент кода, "Hello World!"
должен находиться в индексе 2
среды, независимо от того, какой метод мы используем.
Как это работает
Причина, по которой это работает, заключается в том, что существует стандарт для того, как аргументы командной строки и окружение размещаются в памяти процесса при выполнении программы: Массив среды charуказатели размещаются сразу после массива аргументов командной строки.
Поскольку эти массивы завершаются пустой строкой, это будет выглядеть так:
+---------+---------------------------------------+
| Args | Environment |
+---------+---------+---------+---------+---------+
| NULL | envp[0] | envp[1] | envp[2] | NULL |
+---------+---------+---------+---------+---------+
^ ^ ^
| | |
argv[0] argv[1] ... argv[3]
Надеюсь, искусство ASCII поможет вам понять, почему argv[3]
означает то же самое, что и environ[2]
когда мы выполняем программу следующим образом.