如何将字符串向量传递给 execv

问题描述 投票:0回答:7

我发现构建程序参数列表的最简单方法是作为字符串向量。但是,execv 需要第二个参数为字符数组。让它接受字符串向量的最简单方法是什么?

c++ string vector
7个回答
21
投票

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);

3
投票

是的,通过利用

vector
使用的内部数组可以非常干净地完成此操作。最好不要在向量中使用 C++ 字符串,以及
const_cast
字符串文字和
string.c_str()
char*

这将起作用,因为标准保证其元素连续存储(请参阅https://stackoverflow.com/a/2923290/383983

#include <unistd.h>
#include <vector>

using std::vector;

int main() {
  vector<const char*> command;

  // do a push_back for the command, then each of the arguments
  command.push_back("echo");
  command.push_back("testing");
  command.push_back("1");
  command.push_back("2");
  command.push_back("3");

  // push NULL to the end of the vector (execvp expects NULL as last element)
  command.push_back(NULL);

  // pass the vector's internal array to execvp
  execvp(command[0], const_cast<char* const*>(command.data()));
  return 1;
}

代码改编自:如何将向量传递给 execvp

执行

const_cast
以避免“从字符串常量到‘char*’的不推荐转换”。字符串文字在 C++ 中实现为
const char*
const_cast
是这里最安全的演员形式,因为它只删除
const
并且不做任何其他有趣的事情。
execvp()
无论如何都不会编辑这些值。

如果你想避免所有的强制转换,你必须通过将所有值复制到

char*
类型来使代码复杂化,这并不值得。

尽管如果您想要传递给

execv
/
execl
的参数数量已知,则用 C 语言编写会更容易。


2
投票

execv
的原型是:

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

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

你有

vector<string>
。 找出该向量的大小并创建一个指向 char 的指针数组。 然后循环遍历向量,并为向量中的每个
string
设置数组的相应元素以指向它。


2
投票

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

我最终在

std::basic_string<char const*>
中构建了参数列表。然后我调用
c_str()
方法并对结果执行
const_cast<char* const*>
以获得
execv
接受的格式的列表。

对于组合参数,我

new
编辑了字符串(由普通字符组成的普通字符串;)),获取它们的
c_str()
并让它们泄漏。

需要

const_cast
才能删除额外的
const
,因为给定字符串类型的
c_str()
方法会返回
char const* const*
iirc。键入此内容,我想我可以使用
std::basic_string<char*>
但我想我有一个理由......


我很清楚

const
转换和内存泄漏看起来有点粗鲁,确实是不好的做法,但由于
execv
取代了整个过程,所以无论如何都没关系。


2
投票

您无法更改 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() 以外的名称。

注意:我只是凭空写下这个。它可能不起作用。它甚至可能无法编译;-)


0
投票

这就是我最终所做的:

  1. std::vector<std::string>
    获取我需要的所有参数。
  2. std::vector<const char *>
    之前创建
    execv()
    ,为所有参数保留足够的空间。
  3. 使用
    std::transform()
    转换第二个向量。
  4. 使用
    execv()
    将其喂给
    const_cast<char* const*>(vec.data())

变换通道:

std::transform(stringsVec.cbegin(), stringsVec.cend(), charsVec.begin(),
    [](const std::string &arg)
{
    return arg.c_str();
});

这基本上是@ericcurtin 和@Ferruccio 答案的组合。


0
投票
  
//  Pass std::string to execvp() example:

const size_t BUFFER_SIZE = 1024;

int run(const std::string &s) {

char buf[BUFFER_SIZE];
char* p = buf;

char* argp[BUFFER_SIZE/4];
char** pp = argp;
*(pp++) = p;

for (const auto c:s) {
  char next_char = c;
  if (c == ' ') {
    next_char = '\0';
    *(pp++) = (p + 1);     
  }
  *p++ = next_char;
  *p = '\0';
}
*pp = nullptr;

return(execvp(*argp, (char**)argp));

}

© www.soinside.com 2019 - 2024. All rights reserved.