C++程式與非C++程式的連結
阿新 • • 發佈:2019-01-22
C++
程式中可能包含由其他語言(例如C語言)寫出的內容。不同的語言可能在使用暫存器儲存引數的方式、引數放入堆疊的順序及編譯器傳遞給連結器的方面存在差異,造成程式之間的協作比較困難。例如C++
為支援過載,程式編譯後的名稱與C
語言不同,例如一個foo
函式:
int foo(int x, int y);
在C++
語言編譯後生成的名字就是類似_foo_int_int
的名稱,而C語言編譯後就是_foo
。因此當在C++
宣告引用一個C
程式庫的foo
函式時,在連結過程中,它就會從C
程式庫中去尋找_foo_int_int
函式,而實際上在C
庫中只存在_foo
函式,因此就會出現找不到指定的連結符號的錯誤。
為了解決這類問題,可以在一個extern "c"
extern "c" int foo(int x, int y);
說明函式將以C
連結約定的方式進行連結。 這樣在C++程式中,它就會以_foo
的名稱去從C程式庫中尋找連結的函式,就可以連結成功。
宣告為extern "c"
只是改變了連結方式,但不影響函式的語義,在C++
中,宣告為extern "c"
的函式仍然遵循C++
的型別檢查和引數轉換原則。
除了一條一條地宣告extern "c"
,還可以以下面連結塊的方式提供一組宣告描述連結的約定:
extern "c" { char* strcpy(char*, const char*); int strlen(const char*); extern int length; }
連結塊也可以包裹整個標頭檔案:
extern "c"
{
#include <string.h>
}
C++
提供了_cplusplus
巨集,可以 保證在C檔案下不包含extern "c
“連結約定,而在C++
程式中,包含C
連結約定:
#ifdef _cplusplus
extern "c"{
#endif
char* strcpy(char*, const char*);
int strlen(const char*);
...
#ifdef _cplusplus
}
#endif
不使用extern "c"
連結約定造成連結錯誤的示例:
/**************************************
* foolib.h *
* *
* 一個簡單C程式庫的標頭檔案 *
**************************************/
int foo(int, int);
/**************************************
* foolib.c *
* *
* 一個簡單C程式庫的定義檔案 *
**************************************/
#include <stdio.h>
#include "foolib.h"
int foo(int x, int y)
{
printf("x = %d, y = %d\n", x, y);
return x;
}
/****************************************
* foolib_caller.cpp *
* *
* 呼叫C程式庫的函式的C++程式 *
****************************************/
#include <iostream>
#include "foolib.h"
int main()
{
int x =10;
int y = 20;
int z = foo(x, y);
std::cout<<"foo(x,y)呼叫成功,結果為"<<z<<std::endl;
}
首先構建foolib.c
檔案構建C
程式庫libfoolib.a
,然後連結到C++
程式中,由於兩種模式編譯出的函式名稱不同,連結失敗,找不到函式定義。
現在在C++程式中新增連結定義,宣告foolib.h中的函式都是以C語言的模式進行連結的,現在可以成功連結。
/****************************************
* foolib_caller.cpp *
* *
* 呼叫C程式庫的函式的C++程式 *
****************************************/
#include <iostream>
extern "C"
{
#include "foolib.h"
}
int main()
{
int x =10;
int y = 20;
int z = foo(x, y);
std::cout<<"foo(x,y)呼叫成功,結果為"<<z<<std::endl;
}