0

我第一次尝试从 Linux 上的 dotnet 服务调用 C++ 包装函数。

C++代码:

extern "C" std::string myfunc(int a, int b){

          std::string mystring = funcB(a, b);
          return mystring;

}

c#代码:

public string myCsharpFunc getA(int a, int b){
     return callMyFunc(a, b);
}
[DllImport("xxxx.so", EntryPoint ="myfunc", CallingConvention= CallingConvertion.Cdecl)]
private static extern string callMyfunc(int a, int b);

dotnet 服务运行良好,我可以进行测试 GET。我也可能遇到 myFunc 并且 funcB 的返回看起来是正确的。但是当 mystring 返回一个分段错误(核心转储)时,一切都崩溃了。似乎即使我将 mystring 返回为“test”,程序也会以同样的方式崩溃。我错过了什么?

4

1 回答 1

0

如果你使用 clang 13 编译这段代码,你会得到一个非常有趣的警告:

warning: 'myfunc' has C-linkage specified, but returns user-defined type 'std::string' (aka 'basic_string<char>') which is incompatible with C [-Wreturn-type-c-linkage]
extern "C" std::string myfunc(int a, int b){
                       ^

(一种针对大量编译器和其他工具编译代码以了解各种编译器和工具对您的代码的看法的简单方法是https://godbolt.org/)。

你常extern "C"说“这个函数应该以一种可以从任何类 C 的 API 调用的方式链接和提供”。但是由于std::string它是一个 C++ 类,它不是可以从 C. 中使用的东西extern "C",尽管它暗示了什么,但它并没有真正起作用。

当您尝试通过 .NET 调用此函数时,它不起作用并且以各种有趣的方式失败。

您应该使用具有有效 C 链接的数据类型。大概是char*这里。.NET 中的类型编组将自动将 C 转换为char*C# string,反之亦然。

内存分配也有一些微妙之处。如果您返回char *通过 分配的 a ,则malloc必须正确地特别注意free它。请参阅pinvoke:如何释放 malloc 的字符串?更多细节。

于 2022-01-19T03:38:57.777 回答