用 std::vector<std::string> 替换命令行参数 int argc 和 char** argv
Posted
技术标签:
【中文标题】用 std::vector<std::string> 替换命令行参数 int argc 和 char** argv【英文标题】:replacing the command line arguments int argc and char** argv with std::vector<std::string> 【发布时间】:2020-05-19 07:03:19 【问题描述】:在this post 之后,我找到了my other problem 的临时解决方法,我想知道是否可以将int argc, char** argv
替换为std::vector<std::string>
变量/对象。
考虑虚构的代码:
#include <iostream>
#include <CloseLibrary>
void someFunction(int argc, char** argv)
for (int i = 0; i < argc; ++i)
std::cout << argv[i] << std::endl;
int myFunc(int argc, char** argv)
someFunction(argc, argv);
return 0;
CloseLibrary
是一个封闭库,我无权访问源代码,而该库中的 someFunction
函数需要 int argc, char** argv
命令行参数。但是对于some reason,我的代码中不能有双指针char**
。
Here in this post 提出了类似我需要的东西,但我不知道如何使用它。我可以这样写代码吗:
#include <iostream>
#include <CloseLibrary>
#include <vector>
void someFunction(int argc, char** argv)
for (int i = 0; i < argc; ++i)
std::cout << argv[i] << std::endl;
int myFunc("args", [](std::vector<std::string> args)
std::vector<char *> cstrs;
cstrs.reserve(args.size());
for (auto &s : args) cstrs.push_back(const_cast<char *>(s.c_str()));
someFunction(cstrs.size(), cstrs.data());
return 0;
或者也许有更规范的方法来做到这一点?如果您能帮助我找到正确的方法并理解解决方案,我将不胜感激。提前感谢您的帮助。
P.S.1. char* argv[]
方法在函数体中可以,但在输入中不行。我不知道为什么pybind11会这样做!
P.S.2. Here on pybind11 gitter,建议这样做:
void run(const std::vector<std::string>& args)
for(auto&& e : args) std::cout << e << '\n';
P.S.3. 也建议在 pybind11 Gitter 上:
char** argv = new char*[vec.size()]; // just like malloc(sizeof(char*)*vec.size());
for (int i = 0; i < vec.size(), i++)
argv[i] = new char[vec[i].size()];
memcpy(argv[i], vec[i].data(), vec[i].size()); // or strcpy
【问题讨论】:
std::vector args(argv, argv + argc) 怎么样? ? @André 我猜应该没问题。请在帖子中详细说明? 我可能误解了你的问题。你想用 std::vector args( argv, argv+argc ) “简单”地遍历你的 args 吗?或者你想做相反的事情:从给定的 std::vector 建立一个 char** argv, int argc ? @André 我的问题有两个。 1. 如何获取命令行参数的第二个参数,除了char** argv
或char* arg[]
以外的任何形式。我最初认为我可以使用某种形式的std::vector<std::string>
,但我不确定这是否可能。也许char* argv_
或void* argv_
。 2. 如何将第二个参数转换/解析为char* argv[]
的形式,因为这在函数体中是可能的。
@Foad 不清楚你到底在问什么。请详细说明您需要调用的函数的确切签名以及您有这些限制的原因。
【参考方案1】:
对于它的价值...完全回到您无法将char**
与 pybind11 一起使用的原始问题,一个完整的工作示例,从您发布的部分中清除如下。是的,它不漂亮,但使用指针永远不会。
#include <pybind11/pybind11.h>
#include <iostream>
#if PY_VERSION_HEX < 0x03000000
#define MyPyText_AsString PyString_AsString
#else
#define MyPyText_AsString PyUnicode_AsUTF8
#endif
namespace py = pybind11;
void closed_func(int argc, char** argv)
for (int i = 0; i < argc; ++i)
std::cout << "FROM C++: " << argv[i] << std::endl;
void closed_func_wrap(py::object pyargv11)
int argc = 0;
std::unique_ptr<char*[]> argv;
// convert input list to C/C++ argc/argv
PyObject* pyargv = pyargv11.ptr();
if (PySequence_Check(pyargv))
Py_ssize_t sz = PySequence_Size(pyargv);
argc = (int)sz;
argv = std::unique_ptr<char*[]>new char*[sz];
for (Py_ssize_t i = 0; i < sz; ++i)
PyObject* item = PySequence_GetItem(pyargv, i);
argv[i] = (char*)MyPyText_AsString(item);
Py_DECREF(item);
if (!argv[i] || PyErr_Occurred())
argv = nullptr;
break;
// bail if failed to convert
if (!argv)
std::cerr << "argument is not a sequence of strings" << std::endl;
return;
// call the closed function with the proper types
closed_func(argc, argv.get());
PYBIND11_MODULE(HelloEposCmd, m)
m.def("run", &closed_func_wrap, "runs the HelloEposCmd");
编译后可以按预期使用:
$ python - a b c d=13
>>> import HelloEposCmd
>>> import sys
>>> HelloEposCmd.run(sys.argv)
FROM C++: -
FROM C++: a
FROM C++: b
FROM C++: c
FROM C++: d=13
>>>
【讨论】:
【参考方案2】:您可以使用从给定范围初始化向量的构造函数,其中argv
参数充当起始迭代器,argv+argc
充当结束迭代器。
例如,我通常以以下方式开始我的 main 函数:
int main( int argc, char* argv[] )
std::vector< std::string > args( argv, argv + argc );
for ( auto s : args )
std::cout << s << std::endl;
请注意,这还将捕获第一个参数 (argv[0]),该参数通常(但不一定)包含应用程序启动时的名称。
在你的情况下,你想做相反的事情,从 std::vector 构建一个连续的 char*
数组。我会做类似的事情:
std::vector< char* > rargs( args.size(), 0 ); // Initialize N nullptrs.
for ( int i=0; i<args.size(); ++i )
std::strcpy( rargs[i], args[i].c_str() ); // One-by-one strcpy them
然后你可以将它们传递给一个接受 argc,argv as 的函数
someFunction( rargs.size(), rargs.data() );
【讨论】:
可能值得注意的是,这是std::vector
的迭代器构造函数。 argv
参数充当“开始”迭代器,指向char*
数组中的第一项,而argv + argc
充当“结束”迭代器,指向char*
数组中末尾的一个元素.
等等,char* argv[]
也不允许作为主函数的输入。 :(
我还必须将int argc, char** argv
提供给someFunction
。这是我无法改变的!
@Foad 在函数参数的上下文中,char**
完全等同于char*[]
。随意使用您喜欢的任何一个,此答案中的代码仍然有效。
@ArthurTacca:实际上,char*[]
“降级”为char**
。您将总是传递一个指针,而从不一个数组。这种区别很重要,因为在被调用的函数中,您无法使用sizeof
确定数组的长度(因为您看到的是指针,而不是数组)。这就是为什么标准使 double 确保你得到 argv
正确 -- argc
告诉你它的大小 并且 它是零终止的。以上是关于用 std::vector<std::string> 替换命令行参数 int argc 和 char** argv的主要内容,如果未能解决你的问题,请参考以下文章
用 boost.python 暴露 std::vector<double>
用 std::vector<std::string> 替换命令行参数 int argc 和 char** argv