網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
前言
在項(xiàng)目開(kāi)發(fā)過(guò)程中,我們底層代碼經(jīng)常用C來(lái)實(shí)現(xiàn),而上層應(yīng)用大都會(huì)用C++實(shí)現(xiàn),這樣我們就涉及到了C和C++相互調(diào)用的情況了。那么,C/C++如何實(shí)現(xiàn)相互調(diào)用呢?
1、為什么會(huì)有差異?
-
編譯方式不同:
C
文件常采用gcc
編譯,而Cpp
文件常采用g++
來(lái)編譯C++
-
支持函數(shù)重載:由于這一特性,
C++
和C
中的同一個(gè)函數(shù),經(jīng)過(guò)編譯后,生成的函數(shù)名稱是不同的。
這樣就導(dǎo)致了C
與C++
之間不能直接進(jìn)行調(diào)用,要解決這一問(wèn)題,就得靠extern "C"
來(lái)輔助了。
2、extern “C”
- extern
extern
關(guān)鍵字我們并不陌生,它是編程語(yǔ)言中的一種屬性,用來(lái)表示變量,函數(shù)等類型的作用范圍。
我們經(jīng)常在
.c
源文件中定義變量或者實(shí)現(xiàn)函數(shù),在.h
頭文件中使用extern
關(guān)鍵字進(jìn)行聲明,方便其他文件調(diào)用。
“C”
編程語(yǔ)言種類繁多,不同語(yǔ)言有不同的編譯規(guī)則,如果想要互相調(diào)用,必須告訴編譯器以什么規(guī)則去編譯文件,這樣才能正常調(diào)用。
其主要作用是:把“C”
當(dāng)作一個(gè)標(biāo)志位,告訴編譯器,下面代碼以C
的方式編譯!
了解其中原理后,我們來(lái)實(shí)操一下!
3、C++調(diào)用C
我們創(chuàng)建3個(gè)文件,分別為main.cpp
、cal.c
、cal.h
。
我們分別使用gcc
和g++
單獨(dú)編譯文件,編譯出cal.o
和main.o
兩個(gè)中間文件,很簡(jiǎn)單,定義了一個(gè)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
的符號(hào)表,看看同一個(gè)函數(shù)embedded_art
不同編譯方式之后的差別。
可以看到,g++
編譯之后,對(duì)函數(shù)名稱進(jìn)行了加工,按照自身的編譯規(guī)則,最終生成了一個(gè)新的函數(shù)名,所以我們?nèi)绻苯诱{(diào)用cal.c
中的embedded_art
肯定是不行的。
正確方式
使用extern "C"
來(lái)使g++
編譯器用C
的方式編譯。
在main.cpp
文件中,我們引入cal.h
的位置,添加extern "C"
extern "C" { #include "cal.h" }
再次進(jìn)行編譯,即可!
可以看到符號(hào)表中,該函數(shù)名稱正常,然后我們將中間文件鏈接起來(lái),執(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個(gè)文件,分別為main.c
、cal.cpp
、cal.h
。
我們分別使用gcc
和g++
單獨(dú)編譯文件,編譯出cal.o
和main.o
兩個(gè)中間文件,很簡(jiǎn)單,同樣定義了一個(gè)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
的符號(hào)表,看看同一個(gè)函數(shù)embedded_art
不同編譯方式之后的差別。
同樣,不同的編譯器處理方式不同,函數(shù)名稱依舊不同!同樣,需要加入extern "C"
來(lái)告訴編譯器按C
的方式編譯。
我們?cè)?code>cal.h的聲明部分添加,然后重新編譯!
extern "C" { extern void embedded_art(void); }
可以看到符號(hào)表中,該函數(shù)名稱正常,然后我們將中間文件鏈接起來(lái)。
這個(gè)時(shí)候,會(huì)出現(xiàn)報(bào)錯(cuò)
extern "C"
,這是什么情況?
在main.c
文件中,引入了c++
的頭文件cal.h
,因?yàn)?code>"C"在C++
編譯的時(shí)候才能識(shí)別,C
語(yǔ)言中并沒(méi)有這個(gè)關(guān)鍵字。
所以,我們需要在g++
編譯的時(shí)候去加入extern "C"
,而gcc
編譯的時(shí)候跳過(guò),這個(gè)時(shí)候就要提到c++
編譯時(shí)候的特定宏__cplusplus
了,相當(dāng)于一個(gè)閥門了。
我們修改cal.h
文件:
#ifdef __cplusplus extern "C" { #endif extern void embedded_art(void); #ifdef __cplusplus } #endif
這樣就確保了,c++
編譯embedded_art
函數(shù)的時(shí)候,采用C
語(yǔ)法編譯,而gcc
編譯的時(shí)候,不作處理。
再次鏈接,執(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ù)
補(bǔ)充:C/C++文件之間函數(shù)的引用
C通過(guò)加"中間層"來(lái)引用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)鍵點(diǎn):本文件之間的函數(shù)調(diào)用,不牽扯到函數(shù)符號(hào)的生成。比如中間層那個(gè)文件:C++格式的聲明,C的引用(return Max(a,b)),不會(huì)牽扯到什么鏈接失敗,那是發(fā)生在編譯期間的,不牽扯到符號(hào)之間的解析。
總結(jié)
C/C++
之間的相互調(diào)用,歸根到底就是:不同的語(yǔ)言有不同的編譯規(guī)則,要想實(shí)現(xiàn)通用,就必須告訴編譯器,按照目標(biāo)語(yǔ)言的規(guī)則進(jìn)行編譯!
原文鏈接:https://blog.csdn.net/dong__ge/article/details/128392355
相關(guān)推薦
- 2022-06-18 Elasticsearches之python使用及Django與Flask集成示例_python
- 2022-11-02 react組件中過(guò)渡動(dòng)畫的問(wèn)題解決_React
- 2022-09-30 QT實(shí)現(xiàn)多文件拖拽獲取路徑的方法_C 語(yǔ)言
- 2023-06-21 python?import?引用上上上級(jí)包的三種方法_python
- 2022-04-09 C#8.0中的索引與范圍功能介紹_C#教程
- 2022-07-22 Python動(dòng)態(tài)屬性有什么用
- 2022-12-19 Oracle?數(shù)據(jù)庫(kù)啟動(dòng)過(guò)程的三階段、停庫(kù)四種模式詳解_oracle
- 2022-07-25 基于?Redis?實(shí)現(xiàn)接口限流的方式_Redis
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支