4

I'm working on a dynamic library, is it possible to have a function output a custom class object when using extern "C" or am I limited to data types native to C.

For example, could I have

extern "C" std::string func(const std::string& str);

So that I can get that function and use it after loading the library and getting the function symbol?

std::string result = func("Lol");
Adriano
  • 80
  • 11
  • 1
    See if this bears any interest: [extern "C" function return types](https://gcc.gnu.org/legacy-ml/gcc-help/2011-02/msg00393.html) (GCC mailing list) – Marc.2377 May 27 '22 at 18:01
  • 1
    Interesting compiler differences clang and MSVC issue a warning, but GCC compiles ok - live - https://godbolt.org/z/1KnPT8hPE – Richard Critten May 27 '22 at 18:02
  • 4
    The point of extern C is to remove C++'s name mangling and allow the names to be understood by C (or a language that accepts a C interface). You could return a `std::string`, but there isn't much point. The other language won't know what a `std::string` is. – user4581301 May 27 '22 at 18:03
  • You can have C++ types in `extern "C"` function but you can neither create nor access those types from C. They have to be `void *` or pointers to abstract types. The C compiler has no idea how to provide storage for the `std::string` returned by `func` so that can't work. You have to return a `std:string&` or `std:string*` that the C side can treat as `void*` or pointer to an abstract `struct CppString;`. You also will need to provide an `extern "C"` function to delete the string later. – Goswin von Brederlow May 27 '22 at 18:22
  • The comments here pretend that `extern "C"` only exists to interface with C. It does not. Dart FFI, for example, has no problems using functions with C++ types. Like was said, the point is just to not mangle the names. – sweenish May 27 '22 at 18:49
  • 1
    @sweenish: Even if Dart thinks it knows how to handle C++ types, C++ disagrees. You have undefined behavior all over the place if memory allocation and constructor calls are done by anything not the C++ compiler, if member function calls are done through anything except a C++ member-access expression (possibly a pointer-to-member application expression). And so on and so forth. Perhaps a specific implementation is documented to conform to a specific ABI covering the entire C++ language that makes doing these things from another language possible. But in general it is not. – Ben Voigt May 27 '22 at 19:23
  • @BenVoigt I guess it's a good thing that Dart FFI expects you to compile your C++ to a dynamic library then. – sweenish May 27 '22 at 19:25
  • @sweenish: That's helpful but by no means sufficient. – Ben Voigt May 27 '22 at 19:27
  • I'm just more willing to think that the people at Google who introduced this did their homework, I guess. – sweenish May 27 '22 at 19:34
  • Having to use `extern "C"` should be a sign for caution about not too extensive C++ compatibility. – Sebastian May 27 '22 at 19:54

2 Answers2

3
extern "C" std::string func(const std::string& str);

will give func C-style linkage. func will not be mangled to allow for fun C++ tricks like overloading.

It won't prevent the function from accepting or returning a C++ type, but the calling language will have to know how to interpret the type. For types that are not Standard layout, trivial types (what we used to call POD) this will be difficult-to-impossible.

Side note: Since Standard Library implementations can differ, this can be problematic for a type like std::string even if the caller is C++ code.

user4581301
  • 33,082
  • 7
  • 33
  • 54
0

From the standard:

Linkage from C++ to objects defined in other languages and to objects defined in C++ from other languages is implementation-defined and language-dependent. Only where the object layout strategies of two language implementations are similar enough can such linkage be achieved.

In the context of your question, I interpret this to mean: Yes, you can use C linkage (to skip mangling/simplify symbol names) on C++-specific objects and types, but the environment referencing those symbols needs to be specified such that it can make sense of those objects. As your linking environment is also C++, this should not be a problem, assuming you use binary-compatible versions of the C++ standard library/STL on "both sides".

pmdj
  • 22,018
  • 3
  • 52
  • 103