C和C++如何實現(xiàn)互相調(diào)用詳解
前言
在項目開發(fā)過程中,我們底層代碼經(jīng)常用C來實現(xiàn),而上層應(yīng)用大都會用C++實現(xiàn),這樣我們就涉及到了C和C++相互調(diào)用的情況了。那么,C/C++如何實現(xiàn)相互調(diào)用呢?
1、為什么會有差異?
- 編譯方式不同:
C文件常采用gcc編譯,而Cpp文件常采用g++來編譯C++ - 支持函數(shù)重載:由于這一特性,
C++和C中的同一個函數(shù),經(jīng)過編譯后,生成的函數(shù)名稱是不同的。
這樣就導(dǎo)致了C與C++之間不能直接進行調(diào)用,要解決這一問題,就得靠extern "C"來輔助了。
2、extern “C”
- extern
extern關(guān)鍵字我們并不陌生,它是編程語言中的一種屬性,用來表示變量,函數(shù)等類型的作用范圍。
我們經(jīng)常在
.c源文件中定義變量或者實現(xiàn)函數(shù),在.h頭文件中使用extern關(guān)鍵字進行聲明,方便其他文件調(diào)用。
“C”
編程語言種類繁多,不同語言有不同的編譯規(guī)則,如果想要互相調(diào)用,必須告訴編譯器以什么規(guī)則去編譯文件,這樣才能正常調(diào)用。
其主要作用是:把“C”當作一個標志位,告訴編譯器,下面代碼以C的方式編譯!
了解其中原理后,我們來實操一下!
3、C++調(diào)用C
我們創(chuàng)建3個文件,分別為main.cpp、cal.c、cal.h。

我們分別使用gcc和g++單獨編譯文件,編譯出cal.o和main.o兩個中間文件,很簡單,定義了一個embedded_art的函數(shù)。
# dong @ ubuntu in ~/WorkSpace/Donge_Programs/Unix_Programming_Learning/c_c++_call_test on git:main x [15:57:32] $ ls cal.c cal.h main.cpp # dong @ ubuntu in ~/WorkSpace/Donge_Programs/Unix_Programming_Learning/c_c++_call_test on git:main x [15:57:43] $ gcc -c cal.c # dong @ ubuntu in ~/WorkSpace/Donge_Programs/Unix_Programming_Learning/c_c++_call_test on git:main x [15:57:49] $ g++ -c main.cpp # dong @ ubuntu in ~/WorkSpace/Donge_Programs/Unix_Programming_Learning/c_c++_call_test on git:main x [15:57:55] $ ls cal.c cal.h cal.o main.cpp main.o
下面看一下編譯之后的中間文件cal.o和main.o的符號表,看看同一個函數(shù)embedded_art不同編譯方式之后的差別。

可以看到,g++編譯之后,對函數(shù)名稱進行了加工,按照自身的編譯規(guī)則,最終生成了一個新的函數(shù)名,所以我們?nèi)绻苯诱{(diào)用cal.c中的embedded_art肯定是不行的。
正確方式
使用extern "C"來使g++編譯器用C的方式編譯。
在main.cpp文件中,我們引入cal.h的位置,添加extern "C"
extern "C" {
#include "cal.h"
}
再次進行編譯,即可!

可以看到符號表中,該函數(shù)名稱正常,然后我們將中間文件鏈接起來,執(zhí)行,輸出正確結(jié)果!
# dong @ ubuntu in ~/WorkSpace/Donge_Programs/Unix_Programming_Learning/c_c++_call_test on git:main x [16:18:36] $ g++ main.o cal.o # dong @ ubuntu in ~/WorkSpace/Donge_Programs/Unix_Programming_Learning/c_c++_call_test on git:main x [16:19:54] $ ls a.out cal.c cal.h cal.o main.cpp main.o # dong @ ubuntu in ~/WorkSpace/Donge_Programs/Unix_Programming_Learning/c_c++_call_test on git:main x [16:19:57] $ ./a.out main entry 嵌入式藝術(shù)
4、C調(diào)用C++
我們創(chuàng)建3個文件,分別為main.c、cal.cpp、cal.h。

我們分別使用gcc和g++單獨編譯文件,編譯出cal.o和main.o兩個中間文件,很簡單,同樣定義了一個embedded_art的函數(shù)。
# dong @ ubuntu in ~/WorkSpace/Donge_Programs/Unix_Programming_Learning/c_c++_call_test/c_call_c++ on git:main x [16:24:45] $ g++ -c cal.cpp # dong @ ubuntu in ~/WorkSpace/Donge_Programs/Unix_Programming_Learning/c_c++_call_test/c_call_c++ on git:main x [16:24:52] $ gcc -c main.c # dong @ ubuntu in ~/WorkSpace/Donge_Programs/Unix_Programming_Learning/c_c++_call_test/c_call_c++ on git:main x [16:24:56] $ ls cal.cpp cal.h cal.o main.c main.o
下面看一下編譯之后的中間文件cal.o和main.o的符號表,看看同一個函數(shù)embedded_art不同編譯方式之后的差別。

同樣,不同的編譯器處理方式不同,函數(shù)名稱依舊不同!同樣,需要加入extern "C"來告訴編譯器按C的方式編譯。
我們在cal.h的聲明部分添加,然后重新編譯!
extern "C" {
extern void embedded_art(void);
}

可以看到符號表中,該函數(shù)名稱正常,然后我們將中間文件鏈接起來。

這個時候,會出現(xiàn)報錯
extern "C",這是什么情況?
在main.c文件中,引入了c++的頭文件cal.h,因為"C"在C++編譯的時候才能識別,C語言中并沒有這個關(guān)鍵字。
所以,我們需要在g++編譯的時候去加入extern "C",而gcc編譯的時候跳過,這個時候就要提到c++編譯時候的特定宏__cplusplus了,相當于一個閥門了。
我們修改cal.h文件:
#ifdef __cplusplus
extern "C" {
#endif
extern void embedded_art(void);
#ifdef __cplusplus
}
#endif
這樣就確保了,c++編譯embedded_art函數(shù)的時候,采用C語法編譯,而gcc編譯的時候,不作處理。
再次鏈接,執(zhí)行!
# dong @ ubuntu in ~/WorkSpace/Donge_Programs/Unix_Programming_Learning/c_c++_call_test/c_call_c++ on git:main x [16:45:06] C:1 $ gcc -no-pie cal.o main.o -o main # dong @ ubuntu in ~/WorkSpace/Donge_Programs/Unix_Programming_Learning/c_c++_call_test/c_call_c++ on git:main x [16:46:46] $ ls cal.cpp cal.h cal.o main main.c main.o # dong @ ubuntu in ~/WorkSpace/Donge_Programs/Unix_Programming_Learning/c_c++_call_test/c_call_c++ on git:main x [16:49:01] $ ./main main entry 嵌入式藝術(shù)
補充:C/C++文件之間函數(shù)的引用
C通過加"中間層"來引用C++(不用修改原C++文件)
//C文件
int MyMax(int, int);
int main()
{
int a = 10;
int b = 20;
printf("%d\n", MyMax(a,b));
return 0;
}//C++文件
int Max(int a, int b)
{
return a > b ? a : b;
}//中間層//C++文件
int Max(int ,int);
extern "C"
{
int MyMax(int a, int b)
{
return Max(a, b);
}
}關(guān)鍵點:本文件之間的函數(shù)調(diào)用,不牽扯到函數(shù)符號的生成。比如中間層那個文件:C++格式的聲明,C的引用(return Max(a,b)),不會牽扯到什么鏈接失敗,那是發(fā)生在編譯期間的,不牽扯到符號之間的解析。
總結(jié)
C/C++之間的相互調(diào)用,歸根到底就是:不同的語言有不同的編譯規(guī)則,要想實現(xiàn)通用,就必須告訴編譯器,按照目標語言的規(guī)則進行編譯!
到此這篇關(guān)于C和C++如何實現(xiàn)互相調(diào)用的文章就介紹到這了,更多相關(guān)C和C++互相調(diào)用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++ Boost PropertyTree解析INI文件詳解
Boost PropertyTree庫不僅可以解析JSON,XML格式,還可以直接解析INI格式文件。這篇文章就是為大家介紹一下如何通過Boost PropertyTree解析INI文件,需要的可以參考一下2022-01-01
Qt如何設(shè)置窗口屏幕居中顯示以及設(shè)置大小
這篇文章主要介紹了Qt如何設(shè)置窗口屏幕居中顯示以及設(shè)置大小的相關(guān)資料,需要的朋友可以參考下2017-01-01
C++ 多線程編程建議之 C++ 對多線程/并發(fā)的支持(下)
這篇文章主要介紹的是 C++ 多線程編程建議之 C++ 對多線程/并發(fā)的支持的相關(guān)資料,承接前文 現(xiàn)代 C++ 對多線程/并發(fā)的支持,接下來我們看看回發(fā)生什么吧2021-10-10
C++淺析序列數(shù)據(jù)封裝與優(yōu)化實現(xiàn)方法
封裝是面向?qū)ο缶幊讨械陌褦?shù)據(jù)和操作數(shù)據(jù)的函數(shù)綁定在一起的一個概念,這樣能避免受到外界的干擾和誤用,從而確保了安全,數(shù)據(jù)封裝是一種把數(shù)據(jù)和操作數(shù)據(jù)的函數(shù)捆綁在一起的機制,數(shù)據(jù)抽象是一種僅向用戶暴露接口而把具體的實現(xiàn)細節(jié)隱藏起來的機制2022-12-12

