1

I want to call some C++ functions from C code. There are three files in my project: main.c, cgal_kernel.cpp and cgal_kernel.h.

I get compilation errors when I try to compile them.

Here are the three files.

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;
}

I want cgal_kernel.cpp to be compiled to a shared library file to be used from other languages via their Foreign function interfaces.

My compilation steps, stored inside a bash script are

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

I get the following compilation errors, after running the above build script.

+ 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)  

Where am I going wrong here? I tried removing the "C" from the cgal_kernel.cpp file, in the function signature, then I get the error

+ 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

It seems I am making some elementary mistake, about how C++ functions get called from C code, but I can't seem to figure it out!


EDIT: If I add the extern "C" to the function signature in both cgal_kernel.h and cgal_kernel.cpp files I get the following error:

+ 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);
   ^
4
  • 5
    The extern "C" needs to be in the declaration, not the definition (I think it can be in both) Commented Apr 6, 2017 at 22:25
  • 2
    @Justin and you'll need some #if or macro to make sure it only applies in the C++ environment since C doesn't have extern "C". Commented Apr 6, 2017 at 22:32
  • @Justin Please see edit. I still get errors by adding extern "C" to the header file Commented Apr 6, 2017 at 22:34
  • There is a working example here which may be useful: stackoverflow.com/questions/31903005/… Commented Apr 6, 2017 at 22:42

2 Answers 2

1

The easiest way to call C++ code from C is to write a valid C/C++ header file of this form:

// 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

And proceed to just use it from C. In C++, define the functions exactly the same way you normally would.

For your example:

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 ;
}

Note that your main file should be a C++ file, as we can read from How to mix C and C++

Sign up to request clarification or add additional context in comments.

Comments

1

when mixing C and C++ code, remember that the extern "C" needs to be on the C++ end but is INVALID SYNTAX on the C end. So generally I use a macro when mixing code:

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

then use EXTERN_C on all declarations of any function that must be mutually accessible. That way, it is invisible to the C compiler but avoids name-mangling by the C++ compiler.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.