101

我有一个想从 C++ 调用的 C 函数。我不能使用“ extern "C" void foo()”这种方法,因为 C 函数无法使用 g++ 编译。但它使用 gcc 编译得很好。任何想法如何从 C++ 调用函数?

4

4 回答 4

144

像这样编译C代码:

gcc -c -o somecode.o somecode.c

然后是这样的C++代码:

g++ -c -o othercode.o othercode.cpp

然后使用 C++ 链接器将它们链接在一起:

g++ -o yourprogram somecode.o othercode.o

当您包含 C 函数的声明时,您还必须告诉 C++ 编译器一个 C 标头即将到来。所以othercode.cpp开始:

extern "C" {
#include "somecode.h"
}

somecode.h应包含以下内容:

 #ifndef SOMECODE_H_
 #define SOMECODE_H_

 void foo();

 #endif


(我在这个例子中使用了 gcc,但是任何编译器的原理都是一样的。分别编译为 C 和 C++,然后将它们链接在一起。)

于 2013-05-31T06:29:50.227 回答
74

让我从其他答案和评论中收集点点滴滴,给你一个干净分离的 C 和 C++ 代码的例子:

C部分:

foo.h

#ifndef FOO_H
#define FOO_H

void foo(void);

#endif 

foo.c

#include "foo.h"

void foo(void)
{
    /* ... */
}

gcc -c -o foo.o foo.c.

C++部分:

酒吧.cpp

extern "C" {
  #include "foo.h" //a C header, so wrap it in extern "C" 
}

void bar() {
  foo();
}

编译这个g++ -c -o bar.o bar.cpp

然后将它们链接在一起:

g++ -o myfoobar foo.o bar.o

理由: C 代码应该是纯 C 代码,没有#ifdefs 表示“也许有一天我会用另一种语言调用它”。如果某些 C++ 程序员调用您的 C 函数,那么如何做到这一点是他们的问题,而不是您的问题。如果您是 C++ 程序员,那么 C 标头可能不是您的,您不应该更改它,因此未损坏的函数名称(即extern "C")的处理属于您的 C++ 代码。

extern "C"当然,您可以自己编写一个方便的 C++ 标头,除了将 C 标头包装到声明中之外什么都不做。

于 2013-05-31T08:05:07.653 回答
18

我同意Falken 教授的回答,但是在 Arne Mertz 的评论之后,我想举一个完整的例子(最重要的部分是#ifdef __cplusplus):

一些代码.h

#ifndef H_SOMECODE
#define H_SOMECODE

#ifdef __cplusplus
extern "C" {
#endif

void foo(void);

#ifdef __cplusplus
}
#endif

#endif /* H_SOMECODE */

一些代码.c

#include "somecode.h"

void foo(void)
{
    /* ... */
}

其他代码.hpp

#ifndef HPP_OTHERCODE
#define HPP_OTHERCODE

void bar();

#endif /* HPP_OTHERCODE */

其他代码.cpp

#include "othercode.hpp"
#include "somecode.h"

void bar()
{
    foo(); // call C function
    // ...
}

然后按照 Falken 教授的说明进行编译和链接。

之所以可行,是因为使用 编译时gcc,没有定义宏__cplusplus,所以预处理后somecode.h包含的头文件somecode.c是这样的:

void foo(void);

g++并且当使用, then__cplusplus 进行编译时,定义了,因此包含在其中的标头othercode.cpp现在是这样的:

extern "C" {

void foo(void);

}
于 2013-05-31T07:30:15.973 回答
3

这个答案的灵感来自一个 Arne 的理由是正确的案例。供应商编写了一个曾经同时支持 C 和 C++ 的库;但是,最新版本仅支持 C。代码中留下的以下残留指令具有误导性:

#ifdef __cplusplus
extern "C" {
#endif

这花了我几个小时试图用 C++ 编译。简单地从 C++ 调用 C 要容易得多。

ifdef __cplusplus 约定违反了单一责任原则。使用此约定的代码试图同时做两件事:

  • (1) 在 C 中执行一个函数 -- 和 --
  • (2)在C++中执行相同的函数

这就像同时尝试用美式英语和英式英语写作一样。这会不必要地抛出#ifdef __thequeensenglish 扳手#elif __yankeeenglish 扳手#else 一个无用的工具,它会使代码更难将#endif 读入代码中。

对于简单的代码和小型库, ifdef __cplusplus 约定可能有效;然而,对于复杂的库,最好选择一种或另一种语言并坚持使用。与同时支持两种语言相比,支持其中一种语言所需的维护更少。

这是我为在 Ubuntu Linux 上编译而对 Arne 的代码所做的修改的记录。

foo.h

#ifndef FOO_H
#define FOO_H

void foo(void);

#endif 

foo.c

#include "foo.h"
#include <stdio.h>

void foo(void)
{
     // modified to verify the code was called
     printf("This Hello World was called in C++ and written in C\n");
}

酒吧.cpp

extern "C" {
    #include "foo.h" //a C header, so wrap it in extern "C" 
}

int main() {
  foo();
  return(0);
}

生成文件

# -*- MakeFile -*-
# dont forget to use tabs, not spaces for indents
# to use simple copy this file in the same directory and type 'make'

myfoobar: bar.o foo.o
    g++ -o myfoobar foo.o bar.o 

bar.o: bar.cpp
    g++ -c -o bar.o bar.cpp

foo.o: foo.c
    gcc -c -o foo.o foo.c
于 2018-01-22T03:21:13.487 回答