我有一个想从 C++ 调用的 C 函数。我不能使用“ extern "C" void foo()
”这种方法,因为 C 函数无法使用 g++ 编译。但它使用 gcc 编译得很好。任何想法如何从 C++ 调用函数?
4 回答
像这样编译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++,然后将它们链接在一起。)
让我从其他答案和评论中收集点点滴滴,给你一个干净分离的 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 代码,没有#ifdef
s 表示“也许有一天我会用另一种语言调用它”。如果某些 C++ 程序员调用您的 C 函数,那么如何做到这一点是他们的问题,而不是您的问题。如果您是 C++ 程序员,那么 C 标头可能不是您的,您不应该更改它,因此未损坏的函数名称(即extern "C"
)的处理属于您的 C++ 代码。
extern "C"
当然,您可以自己编写一个方便的 C++ 标头,除了将 C 标头包装到声明中之外什么都不做。
我同意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);
}
这个答案的灵感来自一个 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