【问题标题】:C++ Emulating int main(int argc, char *argv[]) from nodeC++ 从节点模拟 int main(int argc, char *argv[])
【发布时间】:2018-02-21 11:41:13
【问题描述】:

基本上,我正在使用他们的 NAPI 功能将现有的 C++ 文件与我们的 javascript / 节点集成。我让它在一个测试 C++ 文件上工作,所以我知道我的设置工作正常。然而,在实际的 C++ 文件中,它被设计为使用命令行中的 argc 和 argv 从命令行运行。基本上我只需要从我的其他函数内部调用 C++ 中的 main 方法,这意味着没有命令行。所以我必须传入 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)

argc 值工作正常

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

【问题讨论】:

  • 这基本上就是我想要弄清楚的。如果我尝试“测试测试”,这就是我得到的“注意:候选函数不可行:第二个参数 int main(int argc, char *argv[ ])"
  • 不,那是我的愚蠢建议。我看到您可以声明 napi_value argv[2] 然后将项目推送到该数组,但是我没有使用它。我可能会建议尝试main(2,["test1","test2"])main(2,&["test1","test2"])
  • 重要有趣的事实:在程序中调用main 是未定义的行为。可能会发生奇怪的蓝精灵。您最好将main 中的代码移动到具有相同参数的另一个函数,并让main 和您的模拟调用这个其他函数。

标签: c++ arrays node.js node-gyp


【解决方案1】:

argv 是一个指向字符串的指针数组(实际上是 NUL 终止的字符数组),其中元素 0 是程序的名称,元素 1 ... argc-1 是程序参数,元素 @987654324 @ 必须是 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::Newwants some callable type(例如函数指针)注册为名为@9​​87654336@ 的导出的处理程序!从Function::New 文档中复制:

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

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

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. 所以,您可以说它是一个以 NULL 结尾的 NUL 终止字符数组。注意这里NULL = 空指针; NUL = 字符串终止符,即'\0'

【讨论】:

  • “其中第一个值是程序的名称,第二个到 (argc-1)th 是程序参数,argcth 必须是 NULL。”您在那里混合了基于 0 和 1 的索引。 argv[0] 必须是程序名称,argv[argc] 必须是 NULL。如果您将argv[0] 称为“第一个”元素,则argv[argc] 是第(argc+1) 个元素。我会完全避免使用序数,只说“元素 0”、“元素 1 到 argc-1”和“元素编号 argc”。
  • @DanielH:是的;我改写了一下,总是明确指定英文序数和 C 数组索引,但可能只是像你说的那样编写索引不太容易混淆;修复...
猜你喜欢
  • 2020-11-03
  • 2011-07-08
  • 2014-10-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-08
  • 2014-01-10
  • 2014-04-23
相关资源
最近更新 更多