Запуск программы с использованием execv и передача аргументов без повышения argc

Мне дали этот код в классе:

    int main(int argc, char **argv)
    {
        if (argc)
        {
            return 1;
        }

        puts(argv[3]);
        return 0;
    }

Теперь я должен написать вторую программу, которая выполнит это и заставит печатать «Hello World!». Поэтому мне нужно найти способ передать аргументы (я полагаю, с помощью execv), оставив argc равным 0.

Вот что у меня есть на данный момент:

int main()
{
    pid_t pid = fork();

    if (pid == 0)
    {
        char *argv[] = { "filepath", "placeholder",
                            "placeholder", "Hello World!" };
        execv("filepath", argv);
        exit(0);
    }
    else
    {
        waitpid(pid, 0, 0);
    }
    
    return 0;
}

Это будет работать в Linux.

Я попробовал исходное предложение mbj передать 0 в массив аргументов, что, к сожалению, не сработало. Однако, если я поставлю 0 в качестве первого аргумента, argc станет 0, но тогда я получу вывод «LC_MEASUREMENT = de_DE.UTF-8» при попытке распечатать аргументы. Поиск в Google мне тоже не помог.

Я здесь в полной растерянности, поэтому любая помощь приветствуется.

В какой операционной системе это будет работать?

mbj 16.01.2019 22:32

В Linux добавлю в пост

LucaW 16.01.2019 22:37
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
2
1 842
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Хорошо, теперь я понял это после некоторых собственных экспериментов.

Поскольку передача массива, который начинается с NULL (0) в execv, приводит к тому, что программа распечатывает LC_MEASUREMENT=de_DE.UTF-8, я понял, что это должно означать, что argv[3] ссылается на элемент в процессе окружающая обстановка (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 среды, независимо от того, какой метод мы используем.

Как это работает

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

Поскольку эти массивы заканчиваются записью NULL, это будет выглядеть так:

+---------+---------------------------------------+ 
| Args    | Environment                           |
+---------+---------+---------+---------+---------+
|  NULL   | envp[0] | envp[1] | envp[2] |  NULL   | 
+---------+---------+---------+---------+---------+
    ^         ^                   ^                     
    |         |                   |
 argv[0]    argv[1]     ...     argv[3]

Я надеюсь, что искусство ASCII поможет вам понять, почему argv[3] означает то же самое, что и environ[2], когда мы выполняем такую ​​программу.

Спасибо, это решение сработало! Спасибо за отличное объяснение, сделав его действительно легким для понимания.

LucaW 17.01.2019 09:14

Другие вопросы по теме