从C代码调用C ++函数时遇到麻烦

时间:2017-04-06 22:23:51

标签: c++ c

我想从C代码中调用一些C ++函数。我的项目中有三个文件:main.ccgal_kernel.cppcgal_kernel.h

当我尝试编译它时,我遇到了编译错误。

这是三个文件。

cgal_kernel.h

typedef enum{
  LEFT_TURN,
  COLLINEAR,
  RIGHT_TURN
} Orientation;

/* Given points p,q,r determine if the link p-q-r is a left turn, right-turn or collinear
*/
extern Orientation orientation_2 (double px, double py, double qx, double qy, double rx, double ry);  

cgal_kernel.cpp

#include "cgal_kernel.h"

extern "C" Orientation orientation_2 (double px, double py, double qx, double qy, double rx, double ry)  
{
  return LEFT_TURN ;

}

main.c

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

int main(void)
{
  double px = 0.0;
  double py = 0.0;

  double qx = 0.0;
  double qy = 1.0;

  double rx = 1.0;
  double ry = 1.0;

  Orientation test= orientation_2 ( px,  py,  qx,  qy,  rx,  ry);

  printf("Answer is %d\n", test);
  return 0;
}

我想将cgal_kernel.cpp编译为共享库文件,以便通过其外部函数接口从其他语言中使用。

我的编译步骤存储在bash脚本中

export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH 
set -ex # Display compilation process.

rm  -f  *~  *.o  *.so
g++ -c -Wall  -Werror -fPIC cgal_kernel.cpp  # Convert to object file
g++ -shared   cgal_kernel.o -o libcgal_kernel.so      
gcc -g -Wall  main.c -o main -I. -L. -lcgal_kernel

运行上面的构建脚本后,我得到以下编译错误。

+ rm -f *~ *.o *.so
+ g++ -c -Wall -Werror -fPIC cgal_kernel.cpp
In file included from cgal_kernel.cpp:1:0:
cgal_kernel.h: In function ‘Orientation orientation_2(double, double, double, double, double, double)’:
cgal_kernel.h:17:20: error: previous declaration of ‘Orientation orientation_2(double, double, double, double, double, double)’ with ‘C++’ linkage
 extern Orientation orientation_2 (double px, double py, double qx, double qy, double rx, double ry);  
                    ^
cgal_kernel.cpp:3:103: error: conflicts with new declaration with ‘C’ linkage
 extern "C" Orientation orientation_2 (double px, double py, double qx, double qy, double rx, double ry)  

我在哪里错了?我尝试从函数签名中的cgal_kernel.cpp文件中删除"C",然后我收到错误

+ rm -f *~ cgal_kernel.o libcgal_kernel.so
+ g++ -c -Wall -Werror -fPIC cgal_kernel.cpp
+ g++ -shared cgal_kernel.o -o libcgal_kernel.so
+ gcc -g -Wall main.c -o main -I. -L. -lcgal_kernel
/tmp/cclw7kGD.o: In function `main':
/home/gaurish/Dropbox/MyWiki/research_projects/MiCha/main.c:15: undefined reference to `orientation_2'
collect2: error: ld returned 1 exit status

似乎我犯了一些基本的错误,关于如何从C代码调用C ++函数,但我似乎无法弄清楚它!

修改 如果我将extern "C"添加到cgal_kernel.hcgal_kernel.cpp文件中的函数签名,我会收到以下错误:

+ rm -f *~ cgal_kernel.o libcgal_kernel.so
+ g++ -c -Wall -Werror -fPIC cgal_kernel.cpp
+ g++ -shared cgal_kernel.o -o libcgal_kernel.so
+ gcc -g -Wall main.c -o main -I. -L. -lcgal_kernel
In file included from main.c:2:0:
cgal_kernel.h:17:8: error: expected identifier or ‘(’ before string constant
 extern "C" Orientation orientation_2 (double px, double py, double qx, double qy, double rx, double ry);  
        ^
main.c: In function ‘main’:
main.c:15:3: warning: implicit declaration of function ‘orientation_2’ [-Wimplicit-function-declaration]
   Orientation test= orientation_2 ( px,  py,  qx,  qy,  rx,  ry);
   ^

2 个答案:

答案 0 :(得分:1)

从C调用C ++代码的最简单方法是编写此表单的有效C / C ++头文件:

// header guard
#ifdef __cplusplus
extern "C" {
// alternatively, you could have separate C and C++ headers and have
// the extern "C" before each function in your C++ header
#endif

// Valid C header

#ifdef __cplusplus
}
#endif

然后继续使用C.在C ++中,按照通常的方式定义函数。

对于你的例子:

<强> cgal_kernel.h

#ifdef __cplusplus
extern "C" {
#endif

typedef enum{
  LEFT_TURN,
  COLLINEAR,
  RIGHT_TURN
} Orientation;

/* Given points p,q,r determine if the link p-q-r is a left turn, right-turn or collinear
*/
Orientation orientation_2 (double px, double py, double qx, double qy, double rx, double ry);

#ifdef __cplusplus
}
#endif

<强> cgal_kernel.cpp

#include "cgal_kernel.h"

Orientation orientation_2(double px, double py, double qx, double qy, double rx, double ry)  
{
  return LEFT_TURN ;
}

请注意,您的主文件应该是C ++文件,我们可以从How to mix C and C++

中读取

答案 1 :(得分:1)

混合C和C ++代码时,请记住extern "C"需要在C ++端,但在C端是INVALID SYNTAX。所以我通常在混合代码时使用宏:

#ifdef __cplusplus
#define EXTERN_C extern "C"
#else
#define EXTERN_C
#endif

然后对必须可以相互访问的任何函数的所有声明使用EXTERN_C。这样,它对C编译器是不可见的,但避免了C ++编译器的名称修改。