1

Folks, Assuming I have a c++ application / library running which implements say

/* Alloc API */
void* my_alloc(int size) {
    return malloc(sizeof(size));
}

This is not under "extern c".

I have a C dynamic library from which I need to call my_alloc, can I directly call that API?

Like,

int test_my_alloc (int size) {
    int *x;

    x = (int*)my_alloc(size);
    if (x == NULL) {
        return 0;
    } else {
        return 1;
    }
}
Madhava
  • 121
  • 4
  • 4
    You probably wanted `malloc(size);` instead of `malloc(sizeof(size));`. But you will face problems as what you really need is `malloc(size*sizeof(int));` – Spikatrix Mar 11 '15 at 15:53
  • Nope - you need to declare `my_alloc` as `extern "C"` or implement a wrapper in your C++ library which does this. – Paul R Mar 11 '15 at 15:53
  • @CoolGuy that was a type, forget that, I am looking at how to call my_alloc from C library. – Madhava Mar 11 '15 at 15:58
  • @PaulR, I have the restriction of being unable to the existing C++ code, so can''t do that. – Madhava Mar 11 '15 at 15:59
  • 1
    OK - try to remember to include important constraints like this in your question in future. I've sketched out one possible solution in an answer below now. – Paul R Mar 11 '15 at 16:41
  • Why do you ask? Please edit your question to explain that! – Basile Starynkevitch Mar 11 '15 at 16:55

3 Answers3

8

You need to create a stub, e.g.

Stub header:

// stub.h

#ifdef __cplusplus
extern "C" {
#endif

void* my_alloc_c(int size);

#ifdef __cplusplus
}
#endif

Stub implementation:

// stub.cpp

#include "stub.h"
#include "header_where_my_alloc_is_declared.h"

void* my_alloc_c(int size)
{
    return my_alloc(size);
}

Your C code (example):

// my_code.c

#include "stub.h"

int main()
{
    void * p = my_alloc_c(42);
    return 0;
}

Then compile your stub and link it with your C code:

g++ -Wall -c stub.cpp          # compile stub.cpp
gcc -Wall my_code.c stub.o     # compile your C code and link with stub.o
Paul R
  • 208,748
  • 37
  • 389
  • 560
  • This was thought of as well, but unfortunately this involves 100+ API wrappers for which we have to write a library, so this was being considered the last approach if we didn't find any other solution. Anyway looks like there is nothing else that can be done apart from wrapper APIs. – Madhava Mar 11 '15 at 17:48
  • OK - again, this information should have been in the question - if you don't make an effort to explain the whole problem then it's like pulling teeth for anyone trying to provide a solution. – Paul R Mar 11 '15 at 17:50
5

As Paul R. answered, you need a stub code. also, you'll better be sure that your C++ function does not throw exceptions (I guess that a C++ function, called from a C program and main, which throws an uncaught exception is having some undefined behavior). BTW, you should be sure that the constructor of static C++ data (like std::cout) is called "conceptually" before your main in C (so you better link your program with a C++ compiler, not a C one). See the GCC __attribute__(constructor)

In practice, at least on Linux with C++ code compiled by GCC (g++) or by Clang/LLVM (clang++), a C++ function has some mangled name.

You might use some ugly and non-portable trick to call a function by its mangled name. You could dare coding:

 int main(int argc, char**argv) {
   extern void* _Z10my_alloc_ci(int size);
   void * p = _Z10my_alloc_ci(42);
   return 0;
 }

but I am a bit ashamed of giving such silly advice. You could even use asm labels e.g.

extern void*f(int) asm ("_Z10my_alloc_ci");
p = f(42);

However, I feel that you should not have any such approaches, and I am surprized why you need to call a C++ function which is not wrapped around extern "C".

Notice that in theory, C++ functions (without extern "C") could even have a different -and incompatible- calling convention than C functions. I don't know any implementation doing that. So to be safe you should wrap your C++ function with some C++ wrapping using extern "C"

To avoid uncaught exceptions, you might catch all of them in your C++ wrapper:

#include <cstdio>
#include <cstdlib>
extern "C" void* my_alloc_c(int size)  {
  extern void* my_alloc(int);
  try {
    return my_alloc(size);
  } catch (...) {
     ::fprintf(::stderr, "got uncaught C++ exception for my_alloc(%d)\n", 
          size);
    ::fflush(nullptr);
    ::abort();
  }
 }

BTW, if your C++ library is large, you might perhaps try to automatize the generation of the glue code. For example, you could customize GCC using MELT (a Lispy domain specific language to extend GCC) by coding an extension in MELT which would generate the glue code when compiling the C++ header files.

You might be interested in libffi which enables you to (portably) call any (C and probably C++) function of arbitrary signature.

Community
  • 1
  • 1
Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
1

From what I gathered:

  1. You have a C++ library you have no control over (you can't add the extern "C")
  2. You have a C library that must call the C++ library
  3. You can modify your C library to accommodate a solution (you can change the makefile and change the name of the function you want to call)

So, one alternative solution would be to compile your C library with the very same C++ compiler used for that C++ library, if that's acceptable for you.

Note: with C89, you'll possibly need to modify bits of your code (e.g. void * to T * conversions are not implicit anymore in C++), but it would probably be easier than 100+ wrappers.

Note 2: If you're using some C99 features (e.g. the VLAs), then that code will not compile in C++.

paercebal
  • 81,378
  • 38
  • 130
  • 159