从 vector<string> 转换为 vector<char*> 到 char** 时 execvp 不工作
execvp not working when converting from vector<string> to vector<char*> to char**
从字符串向量到 char* 向量再到 char**,当参数以 char** 形式出现时工作正常,但转换似乎有问题,我无法找不同。
有更好的方法吗?
vector<string> args;
/* code that correctly parses args from user input */
pid_t kidpid = fork();
if (kidpid < 0)
{
perror("Internal error: cannot fork.");
return -1;
}
else if (kidpid == 0)
{
// I am the child.
vector<char*>argcs;
for(int i=1;i<args.size();i++)
{
char * temp = new char[args.at(i).length()];
for(int k=0;k<args.at(i).length();k++)
{
temp[k] = args.at(i).at(k);
}
argcs.push_back(temp);
}
char** argv = new char*[argcs.size() + 1];
for (int i = 0; i < argcs.size(); i++)
{
argv[i] = argcs[i];
}
argv[args.size()] = NULL;
execvp(program, args);
return -1;
}
首先,如果您接下来要做的是调用 execvp
.
,那么复制 std::string
是没有意义的
如果execvp
成功,那么它将永远不会return,整个记忆图像将化为乌有(或者,更准确地说,被一个全新的图像所取代)。在构建新图像的过程中,exec*
会将 argv 数组(和环境数组)复制到其中。无论如何,永远不会调用 std::vector
和 std::string
析构函数。
另一方面,如果 execvp
失败,则传递给它的参数将不会被修改。 (Posix: "The argv[]
and envp[]
arrays of pointers and the strings to which those arrays point shall not be modified by a call to one of the exec functions, except as a consequence of replacing the process image.")
无论哪种情况,都不需要复制字符串。您可以使用 std::string::c_str()
提取指向底层 C 字符串的指针(作为 const char*
,但请参见下文)。
其次,如果您使用的是 C++11 或更新版本,std::vector
附带一个 data()
成员函数,return 是指向底层存储的指针。因此,如果您有 std::vector<char*> svec
,那么 svec.data()
将是基础 char*[]
,这就是您要传递给 execvp
.
的内容
因此问题简化为从 std::vector<std::string>
创建 std::vector<char*>
,这很简单:
else if (kidpid == 0) {
// I am the child.
std::vector<char*> argc;
// const_cast is needed because execvp prototype wants an
// array of char*, not const char*.
for (auto const& a : args)
argc.emplace_back(const_cast<char*>(a.c_str()));
// NULL terminate
argc.push_back(nullptr);
// The first argument to execvp should be the same as the
// first element in argc, but we'll assume the caller knew
// what they were doing, and that program is a std::string.
execvp(program.c_str(), argc.data());
// It's not clear to me what is returning here, but
// if it is main(), you should return a small positive value
// to indicate an error
return 1;
}
从字符串向量到 char* 向量再到 char**,当参数以 char** 形式出现时工作正常,但转换似乎有问题,我无法找不同。
有更好的方法吗?
vector<string> args;
/* code that correctly parses args from user input */
pid_t kidpid = fork();
if (kidpid < 0)
{
perror("Internal error: cannot fork.");
return -1;
}
else if (kidpid == 0)
{
// I am the child.
vector<char*>argcs;
for(int i=1;i<args.size();i++)
{
char * temp = new char[args.at(i).length()];
for(int k=0;k<args.at(i).length();k++)
{
temp[k] = args.at(i).at(k);
}
argcs.push_back(temp);
}
char** argv = new char*[argcs.size() + 1];
for (int i = 0; i < argcs.size(); i++)
{
argv[i] = argcs[i];
}
argv[args.size()] = NULL;
execvp(program, args);
return -1;
}
首先,如果您接下来要做的是调用 execvp
.
std::string
是没有意义的
如果execvp
成功,那么它将永远不会return,整个记忆图像将化为乌有(或者,更准确地说,被一个全新的图像所取代)。在构建新图像的过程中,exec*
会将 argv 数组(和环境数组)复制到其中。无论如何,永远不会调用 std::vector
和 std::string
析构函数。
另一方面,如果 execvp
失败,则传递给它的参数将不会被修改。 (Posix: "The argv[]
and envp[]
arrays of pointers and the strings to which those arrays point shall not be modified by a call to one of the exec functions, except as a consequence of replacing the process image.")
无论哪种情况,都不需要复制字符串。您可以使用 std::string::c_str()
提取指向底层 C 字符串的指针(作为 const char*
,但请参见下文)。
其次,如果您使用的是 C++11 或更新版本,std::vector
附带一个 data()
成员函数,return 是指向底层存储的指针。因此,如果您有 std::vector<char*> svec
,那么 svec.data()
将是基础 char*[]
,这就是您要传递给 execvp
.
因此问题简化为从 std::vector<std::string>
创建 std::vector<char*>
,这很简单:
else if (kidpid == 0) {
// I am the child.
std::vector<char*> argc;
// const_cast is needed because execvp prototype wants an
// array of char*, not const char*.
for (auto const& a : args)
argc.emplace_back(const_cast<char*>(a.c_str()));
// NULL terminate
argc.push_back(nullptr);
// The first argument to execvp should be the same as the
// first element in argc, but we'll assume the caller knew
// what they were doing, and that program is a std::string.
execvp(program.c_str(), argc.data());
// It's not clear to me what is returning here, but
// if it is main(), you should return a small positive value
// to indicate an error
return 1;
}