首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C++ 調用 C 函式完整指南:extern "C" 機制、頭檔改造與鏈接實戰

     編輯:關於C語言

一、 核心問題:名稱修飾

C++ 支援函式多載,編譯器會對函式名進行名稱修飾,編碼參數型別等資訊生成唯一符號。C 編譯器不修飾,符號即函式名。直接混合編譯會導致鏈接錯誤:找不到符號。

二、 解決方案:extern "C"

告訴 C++ 編譯器:「以下宣告的函式採用 C 語言鏈接規約 (不修飾名稱)」。

1. 單一函式宣告

// C++ 端
extern "C" void csayhello(char *str); // 宣告為 C 鏈接

int main() {
    csayhello("Hello from C++ to C");
    return 0;
}

2. 批量宣告 (區塊形式) —— 頭檔標準寫法

// my_c_lib.h
#ifdef __cplusplus
extern "C" {
#endif

// 這裡放所有 C 函式宣告、結構體定義、巨集等
int  c_add(int a, int b);
void c_init(void);

#ifdef __cplusplus
}
#endif

3. C 端實現 (無需特殊修飾)

// my_c_lib.c
#include <stdio.h>
#include "my_c_lib.h"

int c_add(int a, int b) { return a + b; }
void c_init(void) { printf("C lib init\n"); }

三、 編譯與鏈接實戰

# 編譯 C++ 檔
g++ -c cpp_main.cpp -o cpp_main.o
# 編譯 C 檔
gcc -c my_c_lib.c -o my_c_lib.o
# 鏈接 (需手動指定 C++ 標準庫)
gcc cpp_main.o my_c_lib.o -lstdc++ -o my_app

若用 g++ 鏈接 (g++ cpp_main.o my_c_lib.o -o my_app),會自動鏈接 libstdc++。

四、 實戰頭檔改造範本

現有 C 頭檔 myheader.h:

typedef struct { int year, month, day; } Date;
int GetWeekNo(Date);

改造為支援 C++ 包含:

#ifndef MYHEADER_H
#define MYHEADER_H

#ifdef __cplusplus
extern "C" {
#endif

typedef struct { int year, month, day; } Date;
int GetWeekNo(Date);

#ifdef __cplusplus
}
#endif

#endif

關鍵細節:__cplusplus 前雙底線,大小寫敏感。巨集包裹確保 C 編譯器忽略 extern "C",C++ 編譯器啟用它。

五、 庫函式與自定義函式

  • 標準庫函式:標準頭檔 (如 <stdio.h>, <string.h>) 內部已包裹 extern "C",C++ 直接 #include <cstdio> 即可。
  • 第三方 C 庫:若其頭檔未包裹,需在 C++ 端包含時手動包裹:
    extern "C" { #include "third_party.h" }
  • 自定義 C 模組:務必按上述範本修改頭檔,確保雙語言相容。

六、 進階注意事項

  1. C++ 類別成員函式:不能用 extern "C" (有 this 指標、名稱修飾複雜)。需寫 C 風格包裝函式轉呼叫。
  2. 全域變數:extern "C" int g_var; 可共享全域變數。
  3. 回呼函式:C 庫接受函式指標回呼時,C++ 端回呼函式必須宣告為 extern "C" 或 static,否則指標型別不匹配。

總結

extern "C" 是 C/C++ 混合編程的基石。核心口訣:「C++ 端宣告包裹,C 端正常實現,頭檔雙重防護,鏈接手動指定庫」。規範化頭檔寫法,一次封裝,雙端通用。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved