简体   繁体   English

从 C++ 代码调用 C 函数

[英]Call a C function from C++ code

I have a C function that I would like to call from C++.我有一个我想从 C++ 调用的 C 函数。 I couldn't use " extern "C" void foo() " kind of approach because the C function failed to be compiled using g++.我无法使用“ extern "C" void foo()类型的方法,因为无法使用 g++ 编译 C 函数。 But it compiles fine using gcc.但它使用 gcc 编译得很好。 Any ideas how to call the function from C++?任何想法如何从 C++ 调用函数?

Compile the C code like this:像这样编译 C 代码:

gcc -c -o somecode.o somecode.c

Then the C++ code like this:然后是这样的C++代码:

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

Then link them together, with the C++ linker:然后使用 C++ 链接器将它们链接在一起:

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

You also have to tell the C++ compiler a C header is coming when you include the declaration for the C function.当您包含 C 函数的声明时,您还必须告诉 C++ 编译器一个 C 头文件即将到来。 So othercode.cpp begins with:所以othercode.cpp以:

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

somecode.h should contain something like: somecode.h应该包含以下内容:

 #ifndef SOMECODE_H_
 #define SOMECODE_H_

 void foo();

 #endif


(I used gcc in this example, but the principle is the same for any compiler. Build separately as C and C++, respectively, then link it together.) (我在这个例子中使用了 gcc,但任何编译器的原理都是一样的。分别作为 C 和 C++ 构建,然后将它们链接在一起。)

Let me gather the bits and pieces from the other answers and comments, to give you an example with cleanly separated C and C++ code:让我从其他答案和评论中收集点点滴滴,为您提供一个带有清晰分离的 C 和 C++ 代码的示例:

The C Part: C部分:

foo.h : foo.h :

#ifndef FOO_H
#define FOO_H

void foo(void);

#endif 

foo.c foo.c

#include "foo.h"

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

Compile this with gcc -c -o foo.o foo.c .gcc -c -o foo.o foo.c编译它。

The C++ Part: C++部分:

bar.cpp bar.cpp

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

void bar() {
  foo();
}

Compile this with g++ -c -o bar.o bar.cppg++ -c -o bar.o bar.cpp编译它

And then link it all together:然后将它们链接在一起:

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

Rationale: The C code should be plain C code, no #ifdef s for "maybe someday I'll call this from another language".理由: C 代码应该是普通的 C 代码,没有#ifdef表示“也许有一天我会用另一种语言调用它”。 If some C++ programmer calls your C functions, it's their problem how to do that, not yours.如果某些 C++ 程序员调用您的 C 函数,那么如何调用是他们的问题,而不是您的问题。 And if you are the C++ programmer, then the C header might not be yours and you should not change it, so the handling of unmangled function names (ie the extern "C" ) belongs in your C++ code.如果您是 C++ 程序员,那么 C 头文件可能不是您的,您不应更改它,因此处理未处理的函数名称(即extern "C" )属于您的 C++ 代码。

You might, of course, write yourself a convenience C++ header that does nothing except wrapping the C header into an extern "C" declaration.当然,您可以为自己编写一个方便的 C++ 头文件,它除了将 C 头文件包装到一个extern "C"声明之外什么都不做。

I agree with Prof. Falken's answer , but after Arne Mertz's comment I want to give a complete example (the most important part is the #ifdef __cplusplus ):我同意Falken 教授的回答,但在 Arne Mertz 的评论之后,我想举一个完整的例子(最重要的部分是#ifdef __cplusplus ):

somecode.h一些代码.h

#ifndef H_SOMECODE
#define H_SOMECODE

#ifdef __cplusplus
extern "C" {
#endif

void foo(void);

#ifdef __cplusplus
}
#endif

#endif /* H_SOMECODE */

somecode.c一些代码

#include "somecode.h"

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

othercode.hpp其他代码.hpp

#ifndef HPP_OTHERCODE
#define HPP_OTHERCODE

void bar();

#endif /* HPP_OTHERCODE */

othercode.cpp其他代码.cpp

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

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

Then you follow Prof. Falken's instructions to compile and link.然后您按照 Falken 教授的说明进行编译和链接。

This works because when compiling with gcc , the macro __cplusplus is not defined, so the header somecode.h included in somecode.c is like this after preprocessing:这是有效的,因为在用gcc编译时,宏__cplusplus没有定义,所以包含在somecode.c的头somecode.h预处理后是这样的:

void foo(void);

and when compiling with g++ , then __cplusplus is defined, and so the header included in othercode.cpp is now like that:当用g++编译时, __cplusplus定义,所以othercode.cpp包含的头文件现在是这样的:

extern "C" {

void foo(void);

}

This answer is inspired by a case where Arne's rationale was correct.这个答案的灵感来自 Arne 的理由是正确的一个案例。 A vendor wrote a library which once supported both C and C++;供应商编写了一个曾经支持 C 和 C++ 的库; however, the latest version only supported C. The following vestigial directives left in the code were misleading:但是,最新版本仅支持 C。代码中留下的以下残留指令具有误导性:

#ifdef __cplusplus
extern "C" {
#endif

This cost me several hours trying to compile in C++.这花了我几个小时试图用 C++ 编译。 Simply calling C from C++ was much easier.简单地从 C++ 调用 C 要容易得多。

The ifdef __cplusplus convention is in violation of the single responsibility principle. ifdef __cplusplus 约定违反了单一职责原则。 A code using this convention is trying to do two things at once:使用此约定的代码试图同时做两件事:

  • (1) execute a function in C -- and -- (1) 在 C 中执行一个函数——和——
  • (2) execute the same function in C++ (2)在C++中执行相同的函数

It's like trying to write in both American and British English at the same time.这就像试图同时用美式和英式英语写作。 This is unnecessarily throwing an #ifdef __thequeensenglish spanner #elif __yankeeenglish wrench #else a useless tool which makes the code harder to read #endif into the code.这是不必要地抛出一个#ifdef __thequeensenglish 扳手#elif __yankeeenglish 扳手#else 一个无用的工具,它使代码更难阅读#endif 到代码中。

For simple code and small libraries the ifdef __cplusplus convention may work;对于简单代码和小型库,ifdef __cplusplus 约定可能有效; however, for complex libraries it is best to pick one language or the other and stick with it.但是,对于复杂的库,最好选择一种语言或另一种语言并坚持使用。 Supporting one of the languages will take less maintenance than trying to support both.与尝试同时支持两种语言相比,支持其中一种语言所需的维护更少。

This is a record of the modifications I made to Arne's code to get it to compile on Ubuntu Linux.这是我为了让它在 Ubuntu Linux 上编译而对 Arne 的代码所做的修改的记录。

foo.h : foo.h :

#ifndef FOO_H
#define FOO_H

void foo(void);

#endif 

foo.c 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");
}

bar.cpp bar.cpp

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

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

Makefile生成文件

# -*- 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM