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

extern "C" 深度解析:跨語言鏈接的關鍵

     編輯:關於C語言

extern "C" 深度解析:跨語言鏈接的關鍵

extern "C" 雙重含義:被修飾目標具有 extern 特性(外部鏈接),且遵循 C 語言鏈接約定。

第一層含義:extern 關鍵字

  1. 單文件擴展作用域:外部變量定義不在文件開頭時,僅從定義處到文件末可見。需在引用前用 extern 聲明,擴展可見範圍。
    例:extern int A; printf("%d", A); A = 10;
  2. 多文件共享變量:僅在一個文件定義,其他文件用 extern 聲明。鏈接器解析符號,避免重複定義錯誤。
    例:file1.c: int A = 5; file2.c: extern int A; printf("%d", A);
  3. 外部函數:函數定義默認即 extern(外部鏈接)。內部函數需加 static。調用處用 extern 聲明(通常放入頭文件)。鏈接時在各模塊搜索定義。

第二層含義:"C" 鏈接約定

問題背景:C++ 支持函數重載,編譯器對重載函數生成不同內部修飾名(Name Mangling),如 _eat_beef、_eat_fish。C 編譯器不修飾,foo 符號即 _foo。
若 C++ 直接調用已編譯的 C 庫函數,符號不匹配導致鏈接失敗。

解決方案:extern "C"

// 告訴 C++ 編譯器:foo 使用 C 鏈接,去庫中找 _foo 而非 _foo_int_int
extern "C" {
    int foo(int x, int y);
}

標準庫頭文件已由廠商加上 extern "C",故可直接 #include 使用。

實戰示例

C 庫源文件 (lib.c)

// lib.h
#ifndef _LIB_H_
#define _LIB_H_
int add(int x, int y);
#endif

// lib.c
#include "lib.h"
int add(int x, int y) { return x + y; }

C++ 調用端

#include <iostream>
extern "C" {
    #include "lib.h"
}
int main() {
    std::cout << add(1, 2) << std::endl; // 正確鏈接到 _add
    return 0;
}

若 C++ 直接 #include "lib.h" 無 extern "C",鏈接器報錯:unresolved external symbol "int __cdecl add(int,int)"。

進階用法:__cplusplus 宏守護

使同一頭文件同時兼容 C/C++ 編譯:

#ifndef _LIB_H_
#define _LIB_H_

#ifdef __cplusplus
extern "C" {
#endif

int add(int x, int y);

#ifdef __cplusplus
}
#endif

#endif
  • C 編譯:__cplusplus 未定義,展開為 extern int add(int, int);。
  • C++ 編譯:__cplusplus 定義,展開為 extern "C" { extern int add(int, int); },指定 C 鏈接。

Windows DLL 場景

Windows 用 C 編譯 DLL 導出函數。C 程序直接調用無問題;C++ 調用時,DLL 導出符號為 C 風格(_func),C++ 期望修飾名。在 DLL 頭文件用 extern "C" 聲明導出函數,即可讓 C++ 正確鏈接。許多第三方 DLL 頭文件均採用此模式。

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