C與C++混合編程

2021-02-20 挖坑小精靈

首先,我先了解一下編譯的過程。

分為四步:預處理(預處理用於將所有的#include頭文件以及宏定義替換成其真正的內容)——編譯(將經過預處理之後的程序轉換成特定彙編代碼(assembly code)的過程)——彙編(彙編過程將上一步的彙編代碼轉換成機器碼)——連結(連結過程將多個目標文以及所需的庫文件(.so等)連結成最終的可執行文件).

可以看下原文,大致了解一下:

https://www.cnblogs.com/carpenterlee/p/5994681.html

在這裡,就不過多分析編譯原理,把重心放在如何實現C與C++混合編程的問題上。

我們知道,C語言的發展快五十年了,它積累很多優秀的項目和庫,丟棄了很可惜,重寫也沒必要,那就研究如何在C++中調用它。

C++調用C語言的原理是什麼?

其實,C++的編譯和C語言是一樣的,都要經過四步。前四步是對文件單獨處理,而最後一步(連結)則是全員處理。

混合編程的」混合「操作發生在連結這一步。

c++連結時候,能夠找到對應的c語言函數的符號,那就意味著實現了混合編程。

先擺出結論:

C++編譯後,函數的符號會加上前後綴(與形參的類型有關),這樣做的好處是可以實現函數的多態(即根據你輸入的形參類型來調用相應的函數)。

而C語言編譯後,妥妥地一個沒有加工的函數名。

所以,要解決的問題是,如何讓C++成功連結上(或者對應上,又或者找得上)C語言的符號。

測試一:c++ 同名的函數編譯,然後反彙編查看符號表。

#include <iostream>
 
int add(int a, int b)
{
   return (a + b); 
}
 
double add(double a, double b)
{
   return (a + b);
}

測試二:gcc編譯C源碼

int add(int a, int b)
{
 return (a + b);
}

使用extern "C" {} ,讓C++兼容C語言。這個是C++特有的符號,為了讓編譯器遵循C語言規則。

測試:

extern "C"
{
 
int add(int a, int b)
{
 
   return (a + b);
}

}

編譯出.o文件:g++ test.cpp -c -o test.o

反彙編輸出:objdump test.o -d > test.i

結果:

用g++編譯輸出的符號與C語言一樣。

這樣,就解決了符號的問題。

實驗一:同一個項目全部有源碼,一次編譯連結

//test.cpp
 
#include <iostream>
#include "clib.h"
 
using namespace std;
int main()
{
 int result;
 
 result = add(1.1,2.0);
 
 cout << "result: " << result << endl;
 
 return 0;
}

//clib.c
 
#include "clib.h"
 
int add(int a, int b)
{
 return (a + b);
}

//clib.h
 
#ifndef __MYLIB_H
#define __MYLIB_H
 
#ifdef __cplusplus        //g++編譯器會定義這個宏,而gcc沒有
extern "C"
{
#endif
 
int add(int a, int b);
 
#ifdef __cplusplus
}
#endif
#endif

實現同一個項目全部有源碼,一次編譯連結的方式是

g++ test.cpp clib.c clib.h -o test

這樣的編譯肯定沒問題,但存在一個大問題:c文件被當作c++源碼來編譯了(因為c++是c的超集),c語言原本的編譯高效就沒了,況且有時候項目的某些源碼就是用c語言來編寫,遵循C語言編譯規則比較好。

那麼怎麼處理?

用gcc單獨編譯 c文件,最後用g++全部連結在一起。

gcc  clib.c  -c  -o  clib.o

g++  test.cpp  clib.o  -o  test 

值得關注的一點是,在很多項目中,我們都能看到.h文件包含以下內容:

這樣做,是為了讓.h文件在g++編譯器中依舊按照C語言的規則來編譯,最終連結時候匹配到C庫。

實驗二: 同一個項目中C是庫,C++是源碼,C++調用C

生成一個靜態庫,這個庫是C語言編寫的。

ar  r  libclib.a  clib.o

然後,我們用test.cpp去連結libclib.a庫。

g++  test.cpp  -lclib -L.  -o  test

編譯成功。

成功的原因是,test.cpp裡包含的 clib.h文件中包含了 extern "C"。

在這裡,再引出一個問題,假如clib.h沒有包含 extern "C"呢?

也很好解決,在test.cpp裡補上。

#include <iostream>
 
extern "C"
{
#include "clib.h"
}
 
using namespace std;
int main()
{
 int result;
 
 result = add(1.1,2.0);
 
 cout << "result: " << result << endl;
 
 return 0;
}

c++想要調用c源碼,但又是c源碼遵循c編譯器的規則,則要使用extern "C"。

相關焦點

  • python+C、C++混合編程的應用
    有的語言專注於簡單高效,比如python,內建的list,dict結構比c/c++易用太多,但同樣為了安全、易用,語言也犧牲了部分性能。在有些領域,比如通信,性能很關鍵,但並不意味這個領域的coder只能苦苦掙扎於c/c++的陷阱中,比如可以使用多種語言混合編程。
  • C/C++還能混合編程?這讓我事半功倍
    什麼是C/C++混合編程?我們都知道C是一個結構化語言,它的重點在於算法和數據結構。C程序的設計首要考慮的是如何通過一個過程,對輸入(或環境條件)進行運算處理得到輸出(或實現過程 (事務)控制)對於C++,首要考慮的是如何構造一個對象模型,讓這個模型能夠契合與之對應的問題域,這樣就可以通過獲取對象的狀態信息得到輸出或實現過程(事務)控 制那麼什麼是C/C++混合編程?
  • C語言與C++混合開發?命中會遇見的extern "C"!
    這一節我們來看下一個好玩的內容,就是C和C++的混合編程,我們來逐步拆解,就能夠明白。回顧下之前的內容,我們的源碼,會經歷預處理,編譯,彙編,連結,而C與C++最終相遇,要解決的問題,會在連結過程遇到,我們來看下具體代碼:add.c
  • C/C++編程筆記:C++中的 const 變量詳解,教你正確認識const用法
    +比c類型轉換更嚴格。測試代碼如下:運行結果:3、C/C++中const異同總結c語言全局const會被存儲到只讀數據段。c++中全局const當聲明extern或者對變量取地址時,編譯器會分配存儲地址,變量存儲在只讀數據段。兩個都受到了只讀數據段的保護,不可修改。c語言中局部const存儲在堆棧區,只是不能通過變量直接修改const只讀變量的值,但是可以跳過編譯器的檢查,通過指針間接修改const值。
  • 【教程資源】c/c++/語言/VB/vb.net視頻教程Visual Basic程序設計編程在線課程
    c/c++/語言/VB/vb.net視頻教程Visual Basic程序設計編程在線課程《需要的可以找我,你就可以擁有這個課程》微信
  • C 2 C++進階篇(1)
    首先談談筆者的水平,只學過c和數據結構,接觸過指針,對於取地址&從來沒有接觸過(因為據說是老師說不符合嚴謹的c....), python
  • 入門必備—常用的C語言編程軟體
    ,除此之外擁有一個好的學習工具能使我們的學習事半功倍,下面我們就點評一下常用的C語言編程軟體。Dev-c++上手和操作比較容易,有著良好的兼容性,支持單步調試等功能,不適合寫大的項目,對於小的程序,算法編程等等完全適合
  • c語言編程軟體
    c語言編程軟體(支持win7/win8)是一款支持多語言開發的開發系統。c語言編程軟體(支持win7/win8)同時支持c語言,c++以及vb語言的開發,軟體能很好的兼容win7以及win8,用戶只需設置軟體兼容性,把它設為win 98,win xp等等。小編為大家提供的c語言編程軟體為vc++6.0。
  • C/C++ 輸入輸出緩衝區
    以下是正文(1)c++中cin、cout,cerr和c的stdin、stdout、stderr都是同步的,即iostream 對象和 and cstdio流是同步的,同步關係如下:同步即表明我們可以在程序中混合用cout和printf或其他對應的流對。
  • Mac OS配置C/C++環境
    本文也可參考我的個人博客:https://leonz_z.gitee.io/face2keyboard/網上關於Mac系統下C/C++環境配置的相關資料較少,或許Mac對於一些編程初學者來說卻是不夠友好
  • C++ C、C++、C#、VC、VC.net以及VC++有什麼區別和聯繫?
    java、c、c++、vc、vc++、vb的區別和聯繫java:分三大平臺 java se (j2se),java ee(j2ee),java me(j2me)java se是java ee和java me的基礎java ee是目前位置企業級開發平臺中最牛的java me是用來開發移動嵌入式程序的,例如手機遊戲
  • Python與C混合編程!是Python和C都不具備的超能力!
    編寫 c => python 的接口文件// vectory_py.cextern "C" { vector<point_t>* new_vector(){ return編寫 ctypes 類型文件from ctypes import *class c_point_t(Structure): _fields_ = [("x", c_int), ("y", c_int)]class Vector(object): lib = cdll.LoadLibrary('.
  • C++伺服器開發完整學習路線C++伺服器開發完整學習路線(含免費學習資料下載地址)
    我寫這篇文章的目的就是為了幫助更多想入行或者想轉行做c++伺服器的新人避免走更多的彎路,最終能夠順利的掌握相關知識找到心儀的工作。一. 基礎階段  c/c++程式語言linux基礎數據結構與算法設計模式腳本語言(可選)二.
  • C/C++雜談:函數式編程
    函數式編程和面向過程編程、面向對象編程一樣,是一種編程範式,之前《C/C++雜談:函數指針小結》中提到過以後有機會再順著說一下函數式編程,已經拖了很久了
  • 無廢話--Mac OS, VS Code 搭建c/c++基本開發環境
    搜索「c++」。此時會在當前工作空間目錄生成.vscode配置目錄,同時在配置目錄會生成一個c_cpp_properties.json文件。/c++/hello.cpp",                "-std=c++11",                "-g"            ],            "presentation": {                "echo": true,                "reveal": "always",
  • windows系統安裝gcc編譯器----c/c++語言編譯器
    2.這裡安裝的是c++編譯器,要按安裝別的看下面介紹 4.安裝c 和 c++ 編譯器 請按圖勾上然後去選擇 installation 菜單中的 apply changes 去安裝:  ## 下面是命令方式安裝編譯器:1..安裝好MinGW軟體後,找到安裝文件夾下的bin目錄,默認應該是:c:\MinGW\bin
  • C++中const與C中的const使用對比
    大家好晚上好,今天給大家分享的是,c++中的const的使用,在我們以前學習c語言的時候,我們已經接觸了const的用法,那麼在c++中,const的使用,又會有什麼樣的不同呢?接下來就開始我們的分享吧!每天進步一點點,日積月累你也是專家!
  • 【編程基礎】C++引用簡單介紹
    對於習慣使用C進行開發的朋友們,在看到c++中出現的&符號,可能會犯迷糊,因為在C語言中這個符號表示了取地址符,但是在C++中它卻有著不同的用途
  • C/C++編程筆記:C/C++中的strrchr()函數,到底該怎麼用?
    句法char * strrchr(const char * str,int c)在這裡,str是字符串,c是要定位的字符。它作為int促銷傳遞,但在內部轉換回char。 運用給定C ++中的字符串,我們需要查找字符的最後一次出現,假設為「 a」。
  • 編譯C語言程序,使用 gcc 指令,而C++程序則推薦使用 g++指令!
    可以這樣理解,gcc 是 GCC 編譯器的通用編譯指令,因為根據程序文件的後綴名,gcc 指令可以自行判斷出當前程序所用程式語言的類別,比如:xxx.c:默認以編譯 C 語言程序的方式編譯此文件;xxx.cpp:默認以編譯 C++ 程序的方式編譯此文件。