如何将字符串向量传递给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.hstringvectorusing namespace std; @wallyk: ...以及代码在函数内部的事实!见***.com/questions/5798231/… @YoniZohar:如果execv 有效(没有错误),则该过程被覆盖,所以不会。如果execv 失败,那么可能需要delete【参考方案2】:

是的,通过利用vectors 使用的内部数组,它可以非常干净地完成。最好不要在向量中使用 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&lt;const char*&gt;,那么你可以去掉所有的const_casts。【参考方案3】:

execv 的原型是:

int execv(const char *path, char *const argv[]);

这意味着参数列表是一个指向以 null 结尾的 c 字符串的指针数组。

你有vector&lt;string&gt;。找出该向量的大小并创建一个指向 char 的指针数组。然后循环遍历向量,并为向量中的每个string 设置数组的对应元素指向它。

【讨论】:

这种方法的唯一问题是std::string 存储它的数据通常没有空终止符。在调用 execv() 之前,您必须使用 std::string::c_str() 或在向量手册中的每个字符串中包含空终止符。 "std::string 存储它的数据通常没有空终止符" - 由于 C++11,std::string 需要在其数据缓冲区中存储空终止符.但即使在 C++11 之前,大多数实现还是这样做了,以保持 c_str() 简单。【参考方案4】:

不久前我偶然发现了同样的问题。

我最终在std::basic_string&lt;char const*&gt; 中构建了参数列表。然后我调用了c_str() 方法并对结果进行了const_cast&lt;char* const*&gt; 以获取execv 接受的格式的列表。

对于组合参数,我newed 字符串(由普通字符组成的普通字符串;)),取出他们的c_str() 并让它们泄漏。

const_cast 是删除额外的const 所必需的,因为给定字符串类型的c_str() 方法返回char const* const* iirc。输入这个,我想我可以使用std::basic_string&lt;char*&gt;,但我想我有一个理由......


我很清楚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() 以外的名字。

注意:我只是在脑海中输入了这个。它可能不起作用。它甚至可能无法编译 ;-)

【讨论】:

它无法编译。将 &amp;argv[0] 从 const char** 转换为 char* const* 出现问题

以上是关于如何将字符串向量传递给execv的主要内容,如果未能解决你的问题,请参考以下文章

如何使用向量将多个字符串传递给函数

C ++将文件行传递给字符串向量

execve的返回值是啥

我可以将 const char* 数组传递给 execv 吗?

将字符串向量传递给函数和函数原型问题c ++

在 C++ 中嵌入 Python。传递接收列表列表的字符串向量