1. 程式人生 > >C++程式與非C++程式的連結

C++程式與非C++程式的連結

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

連結成功

參考文獻