使用 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]
的含义相同。
我在 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]
的含义相同。