要从 C 调用 C++ 函数,您需要做两件事。1) 让 C++ 代码知道它将被 C 使用,以便它可以生成 C 友好的符号。2) 隐藏 C 无法理解的任何功能。
第一部分很容易实现,只需像在 C 中一样定义函数(IE 不使用任何仅 C++ 的功能,如名称空间),然后如果定义了 C++,则将它们包装在 extern "C" 块中。您基本上希望您的头文件包含纯 C 代码,然后只需打开顶部的 extern 块,然后在文件底部关闭它(我的示例将使这一点更清楚)。
第二部分有点棘手,但不是太难。在您的情况下,您的函数返回一个 std::string ,它是一个仅限 C++ 的类。它不能在 C 中使用,因此需要用可以在 C 中使用的东西替换,或者它需要隐藏在 C 可以使用的东西后面。为了论证起见,我们假设您不能用 char* 替换 std::string。在这种情况下,您需要从面向 C 的代码中隐藏 std::string。这样做的常用方法是使用不透明指针。
基本上,面向 C 的代码只处理指向某物的指针。它既不知道也不关心的东西。C++ 代码可以在内部自由使用 std::string,但必须确保在与 C API 交互之前将其隐藏。在我的示例中,您可以看到我提供了一个不透明的指针,指向我称为 cppstring 的结构。
在源文件中,cppstring 只是一个包含 std::string 的结构。我已更改您的示例代码以使用新的 cppstring 结构。需要注意的重要一点是,由于 C 代码只能处理指向 cppstring 的指针,因此我们需要在 C++ 代码的堆上创建它并返回指向它的指针。这意味着我们必须为 C 用户提供一些在他们完成后释放它的方法,我在示例中也提供了这种方法。
使用这种技术,您可以将整个 std::string 包装在 C API 后面,允许 C 用户使用 std::string 提供的所有功能。我提供了一个包装 std::string::substr 的示例来向您展示如何。
注意我没有编译也没有测试过这段代码,为了简单起见,我没有包含任何相关的头文件等。不过,它应该足以让你开始。
// C header
#ifdef __cplusplus
extern "C" {
#endif
typedef struct cppstring *cppstring_p;
cppstring_p exec(char *cmd, FILE *pipe);
void free_cppstring(cppstring_p cppstr);
/* example of wrapping std::string::substr for C users */
cppstring_p substr(cppstring_p str, int pos, int count);
#ifdef __cplusplus
}
#endif
// CPP source
struct cppstring {
std::string data;
cppstring(void) {}
cppstring(std::string const& s) : data(s) {}
};
cppstring_p exec(char *cmd, FILE *pipe) {
pipe = _popen(cmd, "r");
if (!pipe) return "ERROR";
char buffer[128];
auto result = new cppstring;
while(!feof(pipe)) {
if(fgets(buffer, 128, pipe) != NULL)
result->data += buffer;
}
_pclose(pipe);
return result;
}
void free_cppstring(cppstring_p cppstr) {
delete cppstr;
cppstr = nullptr;
}
cppstring_p substr(cppstring_p str, int pos, int count) {
assert(str);
return new cppstring(str->data.substr(pos, count));
}