I am trying to call a C++ wrapper function from dotnet service on Linux the first time.
C++ code:
extern "C" std::string myfunc(int a, int b){
std::string mystring = funcB(a, b);
return mystring;
}
c# code:
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);
The dotnet service is running fine and I am able to do a test GET. I could also run into myFunc and the return from funcB looked correct. But everything crashed when mystring is returned with a segmentation fault (core dump). It seems like even if I made mystring returned as "test", the program crashed the same way. What did I miss?
If you compile this code using clang 13, you get a very interesting warning:
(An easy way to compile your code against a ton of compilers and other tools to see what various compilers and tools think about your code is https://godbolt.org/).
You are using
extern "C"
to say "this function should be linked and made available in a way that it can be called from any C-like API". But sincestd::string
is a C++ class, it isn't something that can be used from C.extern "C"
, despite what it suggests, doesn't really work.And when you try and invoke this function through .NET it doesn't work and fails in all sorts of interesting way.
You should use a data type that has a valid C-linkage. Probably a
char*
here. The type marshalling in .NET will automatically convert a Cchar*
to a C#string
and the other way around.There's some subtlety to memory allocation too. If you return a
char *
that was allocated viamalloc
, you will have to take special care tofree
it correctly. See pinvoke: How to free a malloc'd string? for more details.