日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

C和C++如何實現互相調用詳解_C 語言

作者:卍一十二畫卍 ? 更新時間: 2023-02-25 編程語言

前言

在項目開發過程中,我們底層代碼經常用C來實現,而上層應用大都會用C++實現,這樣我們就涉及到了C和C++相互調用的情況了。那么,C/C++如何實現相互調用呢?

1、為什么會有差異?

  • 編譯方式不同C文件常采用gcc編譯,而Cpp文件常采用g++來編譯C++
  • 支持函數重載:由于這一特性,C++C中的同一個函數,經過編譯后,生成的函數名稱是不同的。

這樣就導致了CC++之間不能直接進行調用,要解決這一問題,就得靠extern "C"來輔助了。

2、extern “C”

  • extern

extern關鍵字我們并不陌生,它是編程語言中的一種屬性,用來表示變量,函數等類型的作用范圍。

我們經常在.c源文件中定義變量或者實現函數,在.h頭文件中使用extern關鍵字進行聲明,方便其他文件調用。

“C”

編程語言種類繁多,不同語言有不同的編譯規則,如果想要互相調用,必須告訴編譯器以什么規則去編譯文件,這樣才能正常調用。

其主要作用是:把“C”當作一個標志位,告訴編譯器,下面代碼以C的方式編譯!

了解其中原理后,我們來實操一下!

3、C++調用C

我們創建3個文件,分別為main.cpp、cal.c、cal.h。

image-20221219154545328

我們分別使用gccg++單獨編譯文件,編譯出cal.omain.o兩個中間文件,很簡單,定義了一個embedded_art的函數。

# 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.omain.o的符號表,看看同一個函數embedded_art不同編譯方式之后的差別。

image-20221219160137798

可以看到,g++編譯之后,對函數名稱進行了加工,按照自身的編譯規則,最終生成了一個新的函數名,所以我們如果直接調用cal.c中的embedded_art肯定是不行的。

正確方式

使用extern "C"來使g++編譯器用C的方式編譯。

main.cpp文件中,我們引入cal.h的位置,添加extern "C"

extern "C" {
#include "cal.h"
}

再次進行編譯,即可!

image-20221219161410964

可以看到符號表中,該函數名稱正常,然后我們將中間文件鏈接起來,執行,輸出正確結果!

# 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
嵌入式藝術

4、C調用C++

我們創建3個文件,分別為main.ccal.cpp、cal.h。

image-20221219162526678

我們分別使用gccg++單獨編譯文件,編譯出cal.omain.o兩個中間文件,很簡單,同樣定義了一個embedded_art的函數。

# 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.omain.o的符號表,看看同一個函數embedded_art不同編譯方式之后的差別。

image-20221219162704004

同樣,不同的編譯器處理方式不同,函數名稱依舊不同!同樣,需要加入extern "C"來告訴編譯器按C的方式編譯。

我們在cal.h的聲明部分添加,然后重新編譯!

extern "C" {
extern void embedded_art(void);
}

image-20221219163014548

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

image-20221219163536166

這個時候,會出現報錯extern "C",這是什么情況?

main.c文件中,引入了c++的頭文件cal.h,因為"C"C++編譯的時候才能識別,C語言中并沒有這個關鍵字。

所以,我們需要在g++編譯的時候去加入extern "C",而gcc編譯的時候跳過,這個時候就要提到c++編譯時候的特定宏__cplusplus了,相當于一個閥門了。

我們修改cal.h文件

#ifdef __cplusplus
extern "C" {
#endif

extern void embedded_art(void);

#ifdef __cplusplus
}
#endif

這樣就確保了,c++編譯embedded_art函數的時候,采用C語法編譯,而gcc編譯的時候,不作處理。

再次鏈接,執行!

# 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
嵌入式藝術

補充:C/C++文件之間函數的引用

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

關鍵點:本文件之間的函數調用,不牽扯到函數符號的生成。比如中間層那個文件:C++格式的聲明,C的引用(return Max(a,b)),不會牽扯到什么鏈接失敗,那是發生在編譯期間的,不牽扯到符號之間的解析。

總結

C/C++之間的相互調用,歸根到底就是:不同的語言有不同的編譯規則,要想實現通用,就必須告訴編譯器,按照目標語言的規則進行編譯!

原文鏈接:https://blog.csdn.net/dong__ge/article/details/128392355

欄目分類
最近更新