C調用C++(C++封裝以及C對其調用)

  • 編譯器:

    • gcc和g++編譯器區別
      • gcc是c語言編譯器(也可處理c++);g++是c++編譯器
      • g++對.c和.cpp文件都當c++處理;gcc對.c文件當作c處理,對.cpp當做c++處理
      • g++編譯器在使用時其實調用的是gcc編譯器
      • gcc不能自動鏈接庫文件(.so等),一般用g++來自動鏈接庫文件,要一定使用gcc則需要加上-lstdc++參數(使用libstdc++.so庫)
      • gcc編譯器和g++編譯器在編譯函數時,在相同調用方式下(如都是用_stdcall),對函數名的修飾方式不一樣
    • gcc和g++搜索庫文件的原則
      • 頭文件如果放在/usr/include/下,庫文件放在/lib或/usr/lib或usr/local/lib下編譯器會自動發現對應的庫
      • 如果頭文件和庫文件不在上述位置存放則在編譯器編譯時需要指定對應依賴的頭文件和庫文件的位置,否則編譯器找不到庫文件。指定方式:
        • 使用-I(大寫的i)指定頭文件位置
        • 使用-L指定庫文件位置
        • 使用 -l庫名 指定鏈接的庫名
      • 例子(鏈接mytest/lib下的libgtd.so庫,注意使用-lgtd來指定):g++ test.cpp -o test.txt -L /mytest/lib -lgtd -I /mytest/include
  • 函數名的修飾:

    • 含義:函數的名字修飾(Decorated Name)就是編譯器在編譯期間創建的一個字符串,用來指明函數的定義或原型。LINK程序或其他工具有時需要指定函數的名字修飾來定位函數的正確位置。多數情況下程序員並不需要知道函數的名字修飾,LINK程序或其他工具會自動區分他們。當然,在某些情況下需要指定函數的名字修飾,例如在C++程序中, 爲了讓LINK程序或其他工具能夠匹配到正確的函數名字,就必須爲重載函數和一些特殊的函數(如構造函數和析構函數)指定名字裝飾。
  • 幾種函數調用約定(__cdecl, __stdcall,__fastcall)

    • 用法:調用約定說明符放在函數名前,如int __cdecal add(int a, int b);調用約定一定在函數的聲明和定義中都指定且需保持一致
    • 幾種調用約定的區別
      • 函數被調用時參數(尤其形參)的入棧順序不同
      • 函數出棧是由調用函數還是由被調函數彈出棧的區別
      • 函數名的修飾方式不同。函數名的修飾時編譯器在編譯函數時對函數名進行名稱修飾的操作。這對c語言和c++由很大不同,因爲c++有同名函數的重載,類的構造和析構函數。
    • 由於前兩種區別由編譯器決定,編程者無從干預,所以不再深究。那麼對於第三種(函數名的修飾)區別下面主要說明。
  • 不同編譯環境(c和c++環境)下,各調用約定下對函數名修飾原則

    如函數爲:int functionname(int a, int b)

    • c環境下

      • __cdecl對函數名的修飾:__functionname
      • __stdcall對函數名的修飾:_functionname@number(number爲形參的字節數)
      • __fastcall對函數的修飾:@functionname@number(number爲形參的字節數)
    • c++環境下(爲了重載、繼承特性)

      • 以“?”標識函數名的開始,後跟函數名

      • 如果是__cdecal調用約定,函數名後面接“@@YA”標識參數表的開始;如果是__stdcall調用約定,函數名後面接“@@YG”標識參數表的開始;如果是__fastcall調用約定,函數名後面接“@@YI”標識參數表的開始。

      • 後面再跟參數表,參數表以代號表示(各代號的含義後面說明),參數表的第一項爲該函數的返回值類型,其後依次爲參數的數據類型,指針標識在其所指數據類型前;

      • 參數表後以“@Z”標識整個名字的結束,如果該函數無參數,則以“Z”標識結束。

      • 參數表代號說明

        X--void , 
        D--char, 
        E--unsigned char, 
        F--short, 
        H--int, 
        I--unsigned int, 
        J--long, 
        K--unsigned long, 
        M--float, 
        N--double, 
        _N--bool,
        PA--指針,如果PA表示的是類對象的指針,則PA後接“V+類名+@@” 
        

        那麼上面的functionname函數在__cdecal調用約定下編譯出的函數名修飾爲?add@@YAHHH@Z其餘不再列舉。

    note: VS中編譯C++程序時,編譯器自動定義了一個預處理名字__cplusplus,而編譯標準C時,自動定義名字__STDC__

  • Linux下C調用C++庫(首先要對C++封裝成C)實例:

    • 實例鏈接
    • 實例說明:
      • 生成的libadd.somylib.so、main.bin缺一不可(因爲時動態庫),其中libadd.so是原始c++的實現庫,而mylib.so是c對c++封裝後的庫,main.bin是最終的可執行程序。
      • 勘誤:mylib.so的編譯命令中-la 應爲-ladd,即鏈接上libadd.so庫。
      • 如果沒有按照例子中將libadd.so放到/usr/lib/下,則在編譯mylib.so庫時應該先指定動態庫環境變量LD_LIBRARY_PATH的值(libadd.so的位置)。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章