calling C++library on linux by dotnet

731 Views Asked by At

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?

1

There are 1 best solutions below

0
On

If you compile this code using clang 13, you get a very interesting warning:

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){
                       ^

(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 since std::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 C char* 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 via malloc, you will have to take special care to free it correctly. See pinvoke: How to free a malloc'd string? for more details.