使用fork()和execvp()带参数运行程序的代码验证及参数疑问
问题解答
首先直接给结论:你的代码不会让test程序的ARGV[0]变成-flag,实际运行后,test的ARGV[0]会是/test,而-flag会作为ARGV[1]传递进去。下面详细拆解原因和你代码里需要注意的问题:
1. execvp的参数规则
execvp的第二个参数是字符串数组(char**),这个数组的结构完全对应被执行程序的argv:
- 数组第一个元素(
arguments[0])会成为目标程序的argv[0]——这是Unix系统的约定,通常是程序的路径或名称,几乎所有程序都会依赖这个逻辑 - 数组后续元素是传给程序的命令行参数,对应目标程序的
argv[1]、argv[2]... - 数组必须以
NULL结尾,用来告诉execvp参数列表的结束位置
你的代码里arguments数组的设置完全符合这个规则:
arguments[0] = "/test" // 对应test的argv[0] arguments[1] = "-flag" // 对应test的argv[1] arguments[2] = NULL
所以test程序运行后,输出会是(注意你test代码里少了个空格,实际输出会有点格式小问题,但核心内容是对的):
YOU ENTERED: 2ARGUMENTS ARGV[0]: /test
(如果修复test里的空格,输出会是YOU ENTERED: 2 ARGUMENTS)
2. 你代码里的潜在风险
这里有个很容易踩坑的问题:你把std::string::c_str()的返回值强制转成了char*,这是不安全的:
c_str()返回的是const char*,表示这个指针指向的内存是只读的- 虽然
execvp的参数是char**,但它并不会修改这些字符串,不过C++标准不允许直接把const char*转成char*(这种强制转换属于未定义行为) - 更危险的是,如果
args里的std::string对象在execvp执行前被销毁(比如超出作用域),c_str()返回的指针就会悬空,导致execvp读取无效内存
修复方案
有两种安全的做法:
方案一:改用const char*数组
既然execvp不会修改参数,直接把数组声明为const char*类型,不需要强制转换:
const char* arguments[3]; arguments[0] = args[1].c_str(); arguments[1] = args[2].c_str(); arguments[2] = nullptr;
方案二:复制字符串到可写内存
如果必须使用char*(比如某些旧版本编译器的限制),可以用strdup复制字符串内容,注意在execvp失败时要释放内存(如果execvp成功,进程会被替换,内存会被系统回收,不需要手动释放):
char* arguments[3]; arguments[0] = strdup(args[1].c_str()); arguments[1] = strdup(args[2].c_str()); arguments[2] = nullptr; if (execvp(arguments[0], arguments) == -1) { perror("exec"); // 失败时释放内存避免泄漏 free(arguments[0]); free(arguments[1]); exit(EXIT_FAILURE); }
3. 验证方法
如果你想确认参数传递是否正确,可以修改test程序打印所有argv元素:
int main (int argc, char **argv) { cout << "YOU ENTERED: " << argc << " ARGUMENTS" << endl; for (int i = 0; i < argc; ++i) { cout << "ARGV[" << i << "]: " << argv[i] << endl; } return 0; }
运行后就能清楚看到每个参数的位置了。
内容的提问来源于stack exchange,提问作者D.C.M.
相关产品推荐
相关产品推荐

