2017-04-06 128 views
0

我想從C代碼調用一些C++函數。我的項目中有三個文件:main.ccgal_kernel.cppcgal_kernel.h從C代碼調用C++函數的問題

當我嘗試編譯它們時出現編譯錯誤。

以下是三個文件。

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代碼調用,但我似乎無法弄清楚!


編輯: 如果我在這兩個cgal_kernel.hcgal_kernel.cpp文件,我得到以下錯誤添加extern "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 
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); 
^
+5

外部「C」需要在聲明中,而不是定義(我認爲它可以在兩者中) – Justin

+2

@Justin,你需要一些'#if'或宏來確保它只適用於C++環境,因爲C沒有'extern「C''。 –

+0

@Justin請參閱編輯。我仍然通過在頭文件中添加'extern「C」'來獲得錯誤 – smilingbuddha

回答

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

混合C和C++代碼時閱讀,請記住,extern "C"需要在C++的結束,但C端無效語法。所以一般我用宏混合代碼時:

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

然後在任何函數的所有聲明必須是相互訪問使用EXTERN_C。這樣一來,它對C編譯器來說是不可見的,但是避免了C++編譯器的名稱混亂。