从C库调用C++应用程序代码?

Mad*_*ava 1 c dynamic-library c++11

伙计们,假设我有一个c ++应用程序/库运行实现说

/* Alloc API */
void* my_alloc(int size) {
    return malloc(sizeof(size));
}
Run Code Online (Sandbox Code Playgroud)

这不是"extern c".

我有一个C动态库,我需要调用my_alloc,我可以直接调用该API吗?

Like,

int test_my_alloc (int size) {
    int *x;

    x = (int*)my_alloc(size);
    if (x == NULL) {
        return 0;
    } else {
        return 1;
    }
}
Run Code Online (Sandbox Code Playgroud)

Pau*_*l R 8

你需要创建一个存根,例如

存根标题:

// stub.h

#ifdef __cplusplus
extern "C" {
#endif

void* my_alloc_c(int size);

#ifdef __cplusplus
}
#endif
Run Code Online (Sandbox Code Playgroud)

存根实施:

// stub.cpp

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

void* my_alloc_c(int size)
{
    return my_alloc(size);
}
Run Code Online (Sandbox Code Playgroud)

你的C代码(例子):

// my_code.c

#include "stub.h"

int main()
{
    void * p = my_alloc_c(42);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

然后编译您的存根并将其与您的C代码链接:

g++ -Wall -c stub.cpp          # compile stub.cpp
gcc -Wall my_code.c stub.o     # compile your C code and link with stub.o
Run Code Online (Sandbox Code Playgroud)


Bas*_*tch 5

正如Paul R.回答的那样,你需要一个存根代码.另外,你最好确保你的C++函数不会抛出异常(我猜一个C++函数,从C程序调用main,抛出一个未捕获的异常就是有一些未定义的行为).顺便说一下,你应该确保staticC++数据的构造函数(比如std::cout)在你mainC语言之前被"概念性地"调用(所以你最好用C++编译器而不是C编译器链接你的程序).见海湾合作委员会__attribute__(constructor)

实践中,至少在Linux与C++代码由编译GCC(g++)或通过锵/ LLVM(clang++),C++函数有一些重整名称.

您可能会使用一些丑陋且不可移植的技巧来通过其错位名称来调用函数.你敢于编码:

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

但是我有点羞于提出这样愚蠢的建议.你甚至可以使用asm标签,例如

extern void*f(int) asm ("_Z10my_alloc_ci");
p = f(42);
Run Code Online (Sandbox Code Playgroud)

但是,我觉得你不应该有任何这样的方法,我很惊讶为什么你需要调用一个没有包装的C++函数extern "C".

请注意,理论上,C++函数(没有extern "C")甚至可以具有与C函数不同且不兼容的调用约定.我不知道有任何实现这样做.因此,为了安全起见,您应该使用C++包装来包装C++函数extern "C"

为了避免未捕获的异常,您可能会在C++包装器中捕获所有异常:

#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();
  }
 }
Run Code Online (Sandbox Code Playgroud)

顺便说一句,如果您的C++库很大,您可能会尝试自动生成粘合代码.例如,您可以使用MELT(一种Lispy域特定语言来扩展GCC)来定制GCC,方法是在MELT中编写扩展,这将在编译C++头文件时生成粘合代码.

您可能对libffi感兴趣,它使您(可移植地)调用任意签名的任何(C和可能的C++)函数.