C++ 从节点模拟 int main(int argc, char *argv[])



基本上,我正在使用他们的NAPI功能将现有的C++文件与我们的javascript/节点集成。我让它处理测试C++文件,所以我知道我的设置可以正常工作。但是,在实际的C++文件中,它被设计为从命令行运行,从命令行运行argc和argv。基本上,我只需要从其他函数内部调用 main C++方法,这意味着没有命令行。所以我必须传入 argc 和 argv 的值。argc 只是一个 int,这很容易,但 argc 是一种 char ** 类型,根据我的研究,它看起来像是一个字符数组数组(又名字符串)的数组?

这是我在c ++文件底部的当前代码

void Init(Env env, Object exports, Object module) {
exports.Set("main", Function::New(env, main(2,{"test","test2"})));
}
NODE_API_MODULE(addon, Init)

参数值工作正常

我正在尝试为 argv 创建一个临时/测试值以传入,但我在弄清楚如何使用我的值制作 char ** 类型的数组时遇到了问题。

argv是指向字符串的指针数组(实际上是以 NUL 结尾的字符数组),其中元素 0 是程序的名称,元素 1 ... 程序参数argc-1,元素argc必须NULL1

C++ 中没有数组文本,因此您必须显式创建一个数组变量才能将其传递给函数。更糟糕的是,main被允许修改传递的参数,因此您甚至无法构建字符串文本数组,因为它们是只读的;因此,您必须为每个参数显式分配读/写空间。准系统解决方案可以是为每个参数使用单个缓冲区,并从中构建指针数组:

char argv0[] = "test_program";
char argv1[] = "arg1";
char argv2[] = "arg2";
char *argv[] = {argv0, argv1, argv2, NULL};
main(3, argv);

一个更灵活的方法(特别是如果你必须动态构建你的参数)可以是使用std::vector<std::string>

std::vector<std::string> args = { "test_program", "arg1", "arg2" };
// ... here you may add other arguments dynamically...
args.push_back("arg3"); // whatever
// build the pointers array
std::vector<char *> argv;
for(std::string &s: args) argv.push_back(&s[0]);
argv.push_back(NULL);
main(argv.size()-1, argv.data());

现在,进入您的代码:

void Init(Env env, Object exports, Object module) {
exports.Set("main", Function::New(env, main(2,{"test","test2"})));
}
NODE_API_MODULE(addon, Init)

除了您无法构建argv来传递给这样的main之外,您还试图调用main并将其结果作为第二个参数传递给Function::New,而Function::New希望一些可调用的类型(例如函数指针)注册为名为main的导出的处理程序!从Function::New文档复制:

/// Callable must implement operator() accepting a const CallbackInfo&
/// and return either void or Value.

因此,作为一个简单的示例,您可以通过注册如下回调将 main 导出为不返回任何内容的无参数 JS 函数(我猜是undefined

void MainCallback(const CallbackInfo& info) {
char argv0[] = "test_program";
char argv1[] = "arg1";
char argv2[] = "arg2";
char *argv[] = {argv0, argv1, argv2, NULL};
main(3, argv);
}
void Init(Env env, Object exports, Object module) {
exports.Set("main", Function::New(env, MainCallback));
}
NODE_API_MODULE(addon, Init)

最后,正如其他人所说,从技术上讲,C++main有点神奇 - 从程序内部调用它是未定义的行为;在实践中,在我所知道的任何平台上也可以运行node.js,main是一个完全常规的函数,恰好在启动时由C运行时调用,所以我认为这不会给你带来任何问题。


笔记

  1. 因此,您可以说它是一个以 NUL 结尾的字符数组的 NULL 终止数组。请注意,此处NULL= 空指针;NUL = 字符串终止符,即''.