使用 execv 启动程序并在不引发 argc 的情况下传递参数

Starting program using execv and passing arguments with out raising argc

我在 class 中得到了这个代码:

    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”。谷歌搜索这对我也没有帮助。

我在这里一头雾水,非常感谢您的帮助。

好的,经过我自己的一些试验,我现在明白了。

由于将以 NULL (0) 开头的数组传递给 execv 导致程序打印出 LC_MEASUREMENT=de_DE.UTF-8,我意识到这一定意味着 argv[3] 指的是进程 environment 中的一个元素(LC_MEASUREMENT 是用于在 Linux 中配置区域设置的环境变量之一)。

execv

的解决方案

由于execv会将当前环境复制到新程序中,我们只需要修改环境并将字符串"Hello World!"放在正确的位置,然后再调用execv。事实证明,打印的字符串是环境索引 2 指向的字符串。

要访问当前环境,我们需要在main之外声明environ变量:

external char **environ;

int main() 
{
    ...

然后在调用 execv 之前执行此操作:

        char *argv[] = { NULL };
        environ[2] = "Hello world!";
        execv("filepath", argv);

更简单的解决方案 execve

我们可以使用 execve 函数,而不是在调用 execv 之前声明 external char **environ 和修改当前环境,它让我们传入一个新的字符串数组以用作程序环境:

        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] 的含义相同。