如何从C语言中调用C++函数?

4
我有一个包含以指向C++对象为参数的函数声明的头文件。实现部分在单独的C++文件中。我怎样才能在C中包含此头文件,并在C中使用这些函数,尽管参数需要是C++对象指针?

为什么你不能将你的调用代码切换到C++呢?这并不难,因为C++大多数情况下是向后兼容的。很可能你只需要改变编译方式,而不需要改变代码本身。 - outis
你能修改 C++ 的头文件吗? - jalf
7个回答

7

很不幸,我的第一次尝试回答了错误的问题...

针对您所提出的问题...

正如某位人士指出的那样,您可以传递 void *。这也是我推荐的做法。就 C 而言,指向 C++ 对象的指针应该是完全不透明的。

如果 C++ 函数在全局命名空间中,它们也可以被标记为 extern "C"。以下是一个示例:

myfunc.hpp:

#ifdef __cplusplus
extern "C" {
#endif

extern int myfunction(int, void *ob);

#ifdef __cplusplus
}
#endif

myfunc.cpp:

#include "myfunc.hpp"

void myfunction(int x, void *vobptr)
{
    ClassType *ob = static_cast<ClassType *>(vobptr);
}

afoofile.c

#include "myfunc.hpp"

void frobble(int x, void *opaque_classtype_ptr) {
    myfunction(x, opaque_classtype_ptr);
    /* do stuff with buf */
}

另一种选择是在C语言中使用typedef的创造性用法来实现基本相同的功能。在我看来,这种方式非常丑陋,但以下是一个例子:
myfunc.hpp:
#ifdef __cplusplus
extern "C" {
#else
typedef void ClassType;  /* This is incredibly ugly. */
#endif

extern int myfunction(int, ClassType *ob);

#ifdef __cplusplus
}
#endif

myfunc.cpp:

#include "myfunc.hpp"

void myfunction(int x, ClassType *ob)
{
    // Do stuff with ob
}

afoofile.c

#include "myfunc.hpp"

void frobble(int x, ClassType *opaque_classtype_ptr) {
    myfunction(x, opaque_classtype_ptr);
    /* do stuff with buf */
}

在条件使用 extern "C" 的情况下,更常见的习惯用法可以在我的回答中找到:http://stackoverflow.com/questions/2941126/c-explicit-dll-loading-first-chance-exception-on-non-extern-c-functions/2941360#2941360(它不适合放在评论中)。它不涉及重复原型,因此更不容易出现拼写错误。 - Ken Bloom
@Ken Bloom - 这很有道理,我会编辑我的版本以符合规范,尽管这会使第二个示例中的愚蠢技巧不太清晰。 - Omnifarious
如果这会让指针技巧不够清晰,那么请不要使用它。 - Ken Bloom
如果它看起来非常丑陋,那么什么才是正确的方式呢? - Alexis
1
@Alexis - 另一种方法涉及在C++函数内部使用static_cast。另一种方法的丑陋之处在于,该函数根据看到声明的语言而采用不同的类型。对于普通指针类型,这可能不是问题。但对于函数指针类型,这可能会导致各种奇怪的事情发生。总的来说,像“丑陋的方式”那样玩快速和松散的类型系统只是一个坏主意。 - Omnifarious

4

如果您的C代码只需要传递指针,并最终将其传回到一些实际处理它所指向对象的C ++中,您应该能够在C代码中使用void *,并在返回到C ++时强制转换为T *

如果您计划让C代码实际使用指针,那么您几乎无法摆脱对编译器所做事情的反向工程,并尝试紧密模拟它以使事情正常运作。即使在最好的情况下,这也将是丑陋而脆弱的。


1

创建一个 C++ 的包装器模块,但其外部函数声明为extern "C"。这将允许您从 C 代码中清晰地访问 C++ 代码。自然而然的,该包装器应该用void指针(快速而肮脏的解决方案)或指向不完整的struct类型(只要它们被一致使用,就会提供一定程度的类型安全性) 替换任何无法在 C 中表示的类型(即类)的指针。


0

不行,你必须创建一个与C兼容的抽象层:

typedef struct foowrapper *foohandle;

foohandle foo_create();
void foo_delete(foohandle);

int foo_getvalue(foohandle);
void foo_dosomething(foohandle, const char* str);

0

0
秘密在于“extern C”,其主要目的是防止名称修饰。

-1

请查看此链接:

http://developers.sun.com/solaris/articles/mixing.html

该链接包含以下主题:

  • 使用兼容的编译器

  • 在C++源代码中访问C代码

     - 从C源代码中访问C++代码
  • 混合使用IO流和C标准IO

  • 使用函数指针

  • 处理C++异常

  • 链接程序


1
  1. 在SO上不鼓励发布没有解释、描述或摘要的链接(如果您链接到的页面失效,这将使您的答案毫无用处;这会使读者更难以获得各种答案的概述;一些人喜欢知道他们点击的内容不仅不是垃圾邮件,甚至与问题相关)。
  2. 您甚至没有将其格式化为链接。
- jalf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接