如何将字符串向量传递给execv
Posted
技术标签:
【中文标题】如何将字符串向量传递给execv【英文标题】:How to pass a vector of strings to execv 【发布时间】:2011-04-26 23:55:00 【问题描述】:我发现构建程序参数列表的最简单方法是作为字符串向量。但是, execv 需要一个字符数组作为第二个参数。让它接受字符串向量的最简单方法是什么?
【问题讨论】:
你不能“让它接受”任何它没有被写入接受的东西。但是,您可以将输入转换为它可以理解的格式。 【参考方案1】:execv()
只接受一个字符串指针数组。没有办法让它接受其他任何东西。它是一个标准接口,可以从每种托管语言调用,而不仅仅是 C++。
我已经测试过编译这个:
std::vector<string> vector;
const char *programname = "abc";
const char **argv = new const char* [vector.size()+2]; // extra room for program name and sentinel
argv [0] = programname; // by convention, argv[0] is program name
for (int j = 0; j < vector.size()+1; ++j) // copy args
argv [j+1] = vector[j] .c_str();
argv [vector.size()+1] = NULL; // end of arguments sentinel is NULL
execv (programname, (char **)argv);
【讨论】:
看起来您将程序名称两次传递给 execv,因为 argv[0] 被设置为程序名称。 当我尝试编译程序时,它抱怨argv[0] = programname
。它说test.cpp:10: error: expected constructor, destructor, or type conversion before ‘=’ token
@z-buffer:不知道。它对我来说编译得很好。我唯一没有显示的内容包括unistd.h
、string
、vector
和using namespace std;
。
@wallyk: ...以及代码在函数内部的事实!见***.com/questions/5798231/…
@YoniZohar:如果execv
有效(没有错误),则该过程被覆盖,所以不会。如果execv
失败,那么可能需要delete
。【参考方案2】:
是的,通过利用vector
s 使用的内部数组,它可以非常干净地完成。最好不要在向量中使用 C++ 字符串,以及 const_cast
字符串文字和 string.c_str()
's to char*
。
这会起作用,因为标准保证其元素是连续存储的(请参阅https://***.com/a/2923290/383983)
#include <unistd.h>
#include <vector>
using std::vector;
int main()
vector<char*> commandVector;
// do a push_back for the command, then each of the arguments
commandVector.push_back(const_cast<char*>("echo"));
commandVector.push_back(const_cast<char*>("testing"));
commandVector.push_back(const_cast<char*>("1"));
commandVector.push_back(const_cast<char*>("2"));
commandVector.push_back(const_cast<char*>("3"));
// push NULL to the end of the vector (execvp expects NULL as last element)
commandVector.push_back(NULL);
// pass the vector's internal array to execvp
char **command = commandVector.data();
execvp(command[0], &command[0]);
return 1;
代码改编自:How to pass a vector to execvp
执行const_cast
以避免“从字符串常量到 'char*' 的不推荐转换”。字符串文字在 C++ 中实现为 const char*
。 const_cast
是这里最安全的演员表形式,因为它只删除了 const
并且不做任何其他有趣的事情。 execvp()
无论如何都不会编辑这些值。
如果您想避免所有类型转换,您必须通过将所有值复制到 char*
类型来使代码复杂化,这并不值得。
虽然如果您要传递给execv
/execl
的参数数量是已知的,那么用C 编写会更容易。
【讨论】:
如果你改用vector<const char*>
,那么你可以去掉所有的const_cast
s。【参考方案3】:
execv
的原型是:
int execv(const char *path, char *const argv[]);
这意味着参数列表是一个指向以 null 结尾的 c 字符串的指针数组。
你有vector<string>
。找出该向量的大小并创建一个指向 char 的指针数组。然后循环遍历向量,并为向量中的每个string
设置数组的对应元素指向它。
【讨论】:
这种方法的唯一问题是std::string
存储它的数据通常没有空终止符。在调用 execv()
之前,您必须使用 std::string::c_str()
或在向量手册中的每个字符串中包含空终止符。
"std::string
存储它的数据通常没有空终止符" - 由于 C++11,std::string
需要在其数据缓冲区中存储空终止符.但即使在 C++11 之前,大多数实现还是这样做了,以保持 c_str()
简单。【参考方案4】:
不久前我偶然发现了同样的问题。
我最终在std::basic_string<char const*>
中构建了参数列表。然后我调用了c_str()
方法并对结果进行了const_cast<char* const*>
以获取execv
接受的格式的列表。
对于组合参数,我new
ed 字符串(由普通字符组成的普通字符串;)),取出他们的c_str()
并让它们泄漏。
const_cast
是删除额外的const
所必需的,因为给定字符串类型的c_str()
方法返回char const* const*
iirc。输入这个,我想我可以使用std::basic_string<char*>
,但我想我有一个理由......
我很清楚const
-casting 和内存泄漏看起来有点粗鲁,确实是不好的做法,但由于execv
替换了整个过程,所以无论如何它都无关紧要。
【讨论】:
【参考方案5】:你不能改变 execv 的工作方式(无论如何都不容易),但你可以用你想要的方式重载函数名:
int execv(const string& path, const vector<string>& argv)
vector<const char*> av;
for (const string& a : argv)
av.push_back(a.c_str());
av.push_back(0);
return execv(path.c_str(), &av[0]);
当然,这可能会引起一些混乱。你最好给它一个 execv() 以外的名字。
注意:我只是在脑海中输入了这个。它可能不起作用。它甚至可能无法编译 ;-)
【讨论】:
它无法编译。将&argv[0]
从 const char** 转换为 char* const* 出现问题以上是关于如何将字符串向量传递给execv的主要内容,如果未能解决你的问题,请参考以下文章