日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

【C++ 语言】 C 与 C++ 兼容 ( extern C )

發布時間:2025/6/17 c/c++ 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【C++ 语言】 C 与 C++ 兼容 ( extern C ) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

        • 創建項目
        • 項目源碼說明
        • C++ 中直接調用 C 代碼 ( 無法解析的外部符號 錯誤 )
        • C++ 與 C 編譯結果對比
        • extern "C" 在頭文件中的標準用法
        • 最終的 C / C ++ 兼容 代碼



創建項目


創建 并運行 CMake 項目 :

  • 1. 選擇創建選項 : 在打開的歡迎界面中 , 點擊 右側最下方的 "創建新項目 " 選項 ;

  • 2. 選擇項目類型 : 選擇創建 “CMake 項目” , 在 Android 中主要使用的也是 CMake 配置 NDK C/C++ 代碼 ;

  • 3. 項目配置 : 輸入項目名稱 , 選擇項目位置 , 下面的解決方案名稱會自動生成 , 不勾選最下方的選項 ; 點擊 “創建” 按鈕 , 創建項目 ;


等待項目創建完畢 , 會自動跳轉到程序主界面 ;

  • 4. 自動生成解決方案 : 進入程序主界面后 , 系統會自動生成 CMake 解決方案 , 如果一切順利 , 會有如下結果 :

5. 選擇啟動項 : 點擊綠色的小三角按鈕 “選擇啟動項” , 選擇上面生成的解決方案 “001_CMake_1.exe” 選項 , 如下圖示 ;

  • 6. 運行程序 : 再次點擊 “001_CMake_1.exe” 選項 , 即可運行該控制臺程序 , 在控制臺中打印 “Hello CMake。” ;



項目源碼說明


相關源碼說明 :


① 001_CMake_1.h : 項目頭文件 ;

// 001_CMake_1.h: 標準系統包含文件的包含文件 // 或項目特定的包含文件。#pragma once#include <iostream>// TODO: 在此處引用程序需要的其他標頭。

② 001_CMake_1.cpp : 項目主代碼文件 ;

// 001_CMake_1.cpp: 定義應用程序的入口點。 //#include "001_CMake_1.h"using namespace std;int main() {cout << "Hello CMake。" << endl;return 0; }

C 與 C++ 標準輸出 :

  • C 中的標準輸出 : 直接調用 printf
printf("Hello");
  • C++ 中的標準輸出 : << 此處是 操作符重載 , cout 在 std 命名空間中 ;
cout << "Hello" << endl;

③ CMakeLists.txt ( 工程目錄下 ) : 項目構建配置文件 , 配置 構建工具版本號 , 項目編譯所需的源代碼 ;

# CMakeList.txt: 001_CMake_1 的 CMake 項目,在此處包括源代碼并定義 # 項目特定的邏輯。 # cmake_minimum_required (VERSION 3.8)# 將源代碼添加到此項目的可執行文件。 add_executable (001_CMake_1 "001_CMake_1.cpp" "001_CMake_1.h")# TODO: 如有需要,請添加測試并安裝目標。

④ CMakeLists.txt ( 總目錄下 ) : 頂層的 CMake 文件, 配置全局所有子項目信息 , 這里只有一個子項目 ;

# CMakeList.txt: 頂層 CMake 項目文件,在此處執行全局配置 # 并包含子項目。 # cmake_minimum_required (VERSION 3.8)project ("001_CMake_1")# 包含子項目。 add_subdirectory ("001_CMake_1")


C++ 中直接調用 C 代碼 ( 無法解析的外部符號 錯誤 )


C++ 向下兼容 : C 中大部分代碼都可以在 C++ 中直接使用 ; 但是需要做兼容處理 , 不能直接使用 ;


1. 創建測試文件 : 在上述創建的項目中 , 創建 c_extern.c 和 c_extern.h 兩個文件 ;


2. c_extern.h 頭文件內容 : 在頭文件中定義一個帶參數的方法 ;

#pragma once//任意定義一個方法 , 該方法有若干個參數和返回值 int add(int a, int b);

3. c_extern.c 源文件內容 : 在 C 語言文件中實現上述頭文件中定義的帶參數的方法 ;

#include "c_extern.h"//實現的頭文件中的方法, 用于測試 C 與 C++ 兼容問題 int add(int a, int b) {return 0; }

4. CMake 配置源碼 : 將 “c_extern.c” ( C文件 ) 和 “c_extern.h” ( 頭文件 ) 配置到 CMakeLists.txt 中 ;

# CMakeList.txt: 001_CMake_1 的 CMake 項目,在此處包括源代碼并定義 # 項目特定的邏輯。 # cmake_minimum_required (VERSION 3.8)# 將源代碼添加到此項目的可執行文件。 add_executable (001_CMake_1 "001_CMake_1.cpp" "001_CMake_1.h" "c_extern.c" "c_extern.h")# TODO: 如有需要,請添加測試并安裝目標。

5. 執行結果 : 點擊 001_CMake_1.exe 選項 , 運行程序 ; 彈出 “生成失敗 , 是否要繼續調試?” 的對話框 , 此時


6. 錯誤提示 : 無法解析在 main 函數中調用的 add 方法 ;

嚴重性 代碼 說明 項目 文件 行 禁止顯示狀態 錯誤 LNK1120 1 個無法解析的外部命令 ...\CMakeLists.txt ...\001_CMake_1.exe 1 錯誤 LNK2019 無法解析的外部符號 "int __cdecl add(int,int)" (?add@@YAHHH@Z), 該符號在函數 main 中被引用 ...\CMakeLists.txt ...\001_CMake_1.cpp.obj 1

在 C++ 源碼中直接調用 C 源碼 , 一定會報該錯誤 , 下面分析產生該錯誤的原因 , 以及如何進行兼容處理 ;




C++ 與 C 編譯結果對比


1. 創建對比文件 : 創建 下面 兩個文件 , 分別是 C 代碼 和 C++ 代碼 ;

① c_code.c :

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

② c_plus_code.cpp :

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

C 和 C++ 中代碼內容一模一樣 ;


2. 獲取 c_code.c 編譯過程中的 機器碼文件 : 使用 gcc c_code.c -o c_code.o 命令 , 可以獲取編譯的中間文件 , 輸出到 c_code.o 文件中 ;


3. 獲取 C語言文件編譯后的 機器碼文件中對應的符號 : 使用 nm -A c_code.o 命令 , 可以查看 c_code.o 二進制文件中的符號 ;

輸出詳細內容 :

root@ubuntu:~/001_c_c++# gcc c_code.c -o c_code.o root@ubuntu:~/001_c_c++# root@ubuntu:~/001_c_c++# ls c_code.c c_code.o c_plus_code.cpp root@ubuntu:~/001_c_c++# root@ubuntu:~/001_c_c++# nm -A c_code.o c_code.o:00000000004004d6 T add c_code.o:0000000000601030 B __bss_start c_code.o:0000000000601030 b completed.7594 c_code.o:0000000000601020 D __data_start c_code.o:0000000000601020 W data_start c_code.o:0000000000400410 t deregister_tm_clones c_code.o:0000000000400490 t __do_global_dtors_aux c_code.o:0000000000600e18 t __do_global_dtors_aux_fini_array_entry c_code.o:0000000000601028 D __dso_handle c_code.o:0000000000600e28 d _DYNAMIC c_code.o:0000000000601030 D _edata c_code.o:0000000000601038 B _end c_code.o:0000000000400574 T _fini c_code.o:00000000004004b0 t frame_dummy c_code.o:0000000000600e10 t __frame_dummy_init_array_entry c_code.o:00000000004006d0 r __FRAME_END__ c_code.o:0000000000601000 d _GLOBAL_OFFSET_TABLE_ c_code.o: w __gmon_start__ c_code.o:0000000000400584 r __GNU_EH_FRAME_HDR c_code.o:0000000000400390 T _init c_code.o:0000000000600e18 t __init_array_end c_code.o:0000000000600e10 t __init_array_start c_code.o:0000000000400580 R _IO_stdin_used c_code.o: w _ITM_deregisterTMCloneTable c_code.o: w _ITM_registerTMCloneTable c_code.o:0000000000600e20 d __JCR_END__ c_code.o:0000000000600e20 d __JCR_LIST__ c_code.o: w _Jv_RegisterClasses c_code.o:0000000000400570 T __libc_csu_fini c_code.o:0000000000400500 T __libc_csu_init c_code.o: U __libc_start_main@@GLIBC_2.2.5 c_code.o:00000000004004ea T main c_code.o:0000000000400450 t register_tm_clones c_code.o:00000000004003e0 T _start c_code.o:0000000000601030 D __TMC_END__ root@ubuntu:~/001_c_c++#

4. 分析上述輸出內容 : 由 第一行 c_code.o:00000000004004d6 T add 可以看出 , add 方法編譯后的符號為 add ;


5. 獲取 c_plus_code.cpp 編譯過程中的 機器碼文件 : 使用 gcc c_plus_code.cpp -o c_plus_code.o 命令 , 可以獲取編譯的中間文件 , 輸出到 c_plus_code.o 文件中 ;

root@ubuntu:~/001_c_c++# gcc c_plus_code.cpp -o c_plus_code.o root@ubuntu:~/001_c_c++# ls c_code.c c_code.o c_plus_code.cpp c_plus_code.o root@ubuntu:~/001_c_c++# root@ubuntu:~/001_c_c++# nm -A c_plus_code.o c_plus_code.o:0000000000601030 B __bss_start c_plus_code.o:0000000000601030 b completed.7594 c_plus_code.o:0000000000601020 D __data_start c_plus_code.o:0000000000601020 W data_start c_plus_code.o:0000000000400410 t deregister_tm_clones c_plus_code.o:0000000000400490 t __do_global_dtors_aux c_plus_code.o:0000000000600e18 t __do_global_dtors_aux_fini_array_entry c_plus_code.o:0000000000601028 D __dso_handle c_plus_code.o:0000000000600e28 d _DYNAMIC c_plus_code.o:0000000000601030 D _edata c_plus_code.o:0000000000601038 B _end c_plus_code.o:0000000000400574 T _fini c_plus_code.o:00000000004004b0 t frame_dummy c_plus_code.o:0000000000600e10 t __frame_dummy_init_array_entry c_plus_code.o:00000000004006d0 r __FRAME_END__ c_plus_code.o:0000000000601000 d _GLOBAL_OFFSET_TABLE_ c_plus_code.o: w __gmon_start__ c_plus_code.o:0000000000400584 r __GNU_EH_FRAME_HDR c_plus_code.o:0000000000400390 T _init c_plus_code.o:0000000000600e18 t __init_array_end c_plus_code.o:0000000000600e10 t __init_array_start c_plus_code.o:0000000000400580 R _IO_stdin_used c_plus_code.o: w _ITM_deregisterTMCloneTable c_plus_code.o: w _ITM_registerTMCloneTable c_plus_code.o:0000000000600e20 d __JCR_END__ c_plus_code.o:0000000000600e20 d __JCR_LIST__ c_plus_code.o: w _Jv_RegisterClasses c_plus_code.o:0000000000400570 T __libc_csu_fini c_plus_code.o:0000000000400500 T __libc_csu_init c_plus_code.o: U __libc_start_main@@GLIBC_2.2.5 c_plus_code.o:00000000004004ea T main c_plus_code.o:0000000000400450 t register_tm_clones c_plus_code.o:00000000004003e0 T _start c_plus_code.o:0000000000601030 D __TMC_END__ c_plus_code.o:00000000004004d6 T _Z3addii root@ubuntu:~/001_c_c++#

6. 分析上述輸出內容 : 由 最后一行 c_plus_code.o:00000000004004d6 T _Z3addii 可以看出 , add 方法編譯后的符號為 _Z3addii ;


處理完畢后的文件內容 :

7. 總結 :

  • ① 編譯結果對比 : C 語言 add 方法編譯后的符號是 add , C++ 編譯后的符號是 _Z3addii , 顯然二者不能互相調用 , 因此一旦在 C++ 中調用 add , 就會出現上述無法解析外部符號錯誤 ;
  • ② 兼容 : 如果在 C++ 文件中調用 C 語言庫 , 需要做兼容處理 ;
  • ③ 示例 : 在 Android 中的 NDK 接口是 C++ 語言的 , 但是調用的庫 如 OpenSL ES , FFMPEG 等都是 C語言的庫 , 因此這里就需要用到 C 與 C++ 的兼容 ;
  • ④ 兼容方法 : 使用 extern “C”{} 指定讓大括號中的內容 以 C 語言的方式進行編譯 ; 這樣才能在 C++ 中找到對應的 C 語言中的函數 ; 如下示例 :
extern "C"{#include "c_extern.c" }

編譯過程 : 預處理 -> 編譯 -> 匯編 -> 鏈接;
1. 編譯預處理 : 產生 .i 后綴的預處理文件;
2. 編譯操作 : 產生 .s 后綴的匯編文件;
3. 匯編操作 : 產生 .o 后綴的機器碼二進制文件;
4. 鏈接操作 : 產生可執行文件 ;




extern “C” 在頭文件中的標準用法


extern “C” 用法 :

  • 1. 在引用處使用 : extern “C” {} 可以寫在 引用 頭文件的位置 , 如下 :
// 001_CMake_1.cpp: 定義應用程序的入口點。 //#include "001_CMake_1.h"extern "C" {#include "c_extern.h" }using namespace std;int main() {cout << "Hello CMake。" << endl;//調用 c_extern.h 頭文件中定義的方法//該方法定義在了 C 語言文件中add(1, 2);return 0; }
  • 2. 在頭文件中定義 : extern “C” {} 也可以寫在 頭文件 中 , 一般情況下我們編寫的 C 代碼需要同時兼容 C 和 C++ , 因此 C 語言的頭文件都進行如下定義 :
    • ① __cplusplus 宏 : 該宏定義在 C++ 編譯器中 , 如果是 C 語言編譯器 , 就不會定義該宏 ;
    • ② 使用效果 : 如果在 C++ 編譯環境中 , extern “C” { 和 } 生效 , 在 C 語言編譯環境中 , 不生效 ;
#pragma once//兼容 C 與 C ++ 語言 , 在 C++ 中也可以編譯 C 語言程序 // __cplusplus 是編譯器中定義的 宏 //如果編譯的是 C++ 代碼 , 定義了__cplusplus 宏 , #ifdef __cplusplus 宏會生效//這一組判定 extern "C" { 聲明 , 是否生效 , 如果在 C++ 環境中生效 , C 語言環境中不生效 #ifdef __cplusplus extern "C" { #endif//任意定義一個方法 , 該方法有若干個參數和返回值int add(int a, int b);//這一組判定 } 聲明 , 是否生效 , 如果在 C++ 環境中生效 , C 語言環境中不生效 #ifdef __cplusplus } #endif

注意上述兼容二選一 , 不能同時使用 , 否則會報錯 ;




最終的 C / C ++ 兼容 代碼


最終的 C / C ++ 兼容 代碼 :

  • 1.程序結構 :
  • 2.頂層 CMakeLists.txt : 配置多個項目 ;
# CMakeList.txt: 頂層 CMake 項目文件,在此處執行全局配置 # 并包含子項目。 # cmake_minimum_required (VERSION 3.8)project ("001_CMake_1")# 包含子項目。 add_subdirectory ("001_CMake_1")
  • 3.項目 CMakeLists.txt : 配置單個項目中的多個源文件 ;
# CMakeList.txt: 001_CMake_1 的 CMake 項目,在此處包括源代碼并定義 # 項目特定的邏輯。 # cmake_minimum_required (VERSION 3.8)# 將源代碼添加到此項目的可執行文件。 add_executable (001_CMake_1 "001_CMake_1.cpp" "001_CMake_1.h" "c_extern.c" "c_extern.h")# TODO: 如有需要,請添加測試并安裝目標。
  • 4.c_extern.h :
#pragma once//兼容 C 與 C ++ 語言 , 在 C++ 中也可以編譯 C 語言程序 // __cplusplus 是編譯器中定義的 宏 //如果編譯的是 C++ 代碼 , 定義了__cplusplus 宏 , #ifdef __cplusplus 宏會生效//這一組判定 extern "C" { 聲明 , 是否生效 , 如果在 C++ 環境中生效 , C 語言環境中不生效 #ifdef __cplusplus extern "C" { #endif//任意定義一個方法 , 該方法有若干個參數和返回值int add(int a, int b);//這一組判定 } 聲明 , 是否生效 , 如果在 C++ 環境中生效 , C 語言環境中不生效 #ifdef __cplusplus } #endif
  • 5.c_extern.c :
#include "c_extern.h"//實現的頭文件中的方法, 用于測試 C 與 C++ 兼容問題 int add(int a, int b) {return 0; }
  • 7.001_CMake_1.h :
// 001_CMake_1.h: 標準系統包含文件的包含文件 // 或項目特定的包含文件。#pragma once#include <iostream>// TODO: 在此處引用程序需要的其他標頭。
  • 8.001_CMake_1.cpp :
// 001_CMake_1.cpp: 定義應用程序的入口點。 //#include "001_CMake_1.h" #include "c_extern.h"using namespace std;int main() {cout << "Hello CMake。" << endl;//調用 c_extern.h 頭文件中定義的方法//該方法定義在了 C 語言文件中add(1, 2);return 0; }
  • 9.運行結果 :

總結

以上是生活随笔為你收集整理的【C++ 语言】 C 与 C++ 兼容 ( extern C )的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。