經常看到如下代碼:
#ifdef _cplusplus extern "C" { #endif #include "XXX.h" #ifdef _cplusplus } #endif |
解釋:
這段代碼的含義是,如果當前的程式是C++程式,那麼下面引用的標頭檔是C檔案, 那如果當前程式不是C++呢?難道包含的就不是C檔案了嗎?當然不是,不管當前程式是什麼,這個XXX.h都是一個C檔案
那為什麼還要多此一舉呢?
原因:
C++為了支援函數重載,將編譯後的函數名做了重整(mangled name),比如下面的函數
在C中編譯完的名字就是add,而在C++中,編譯完就變成了add_int_int(舉例而已,實際因編譯器而異),這樣在函數名字後面加上參數的類型,就可以區分不同的重載函數了,比如還有另一個函數
float add(float a, float b) ; |
在C++中,它會被編譯成add_float_float,這就是C++區分重載函數的機制
可是問題也隨之而來
C++進行名字重整,而C不進行重整。當C++程式引用C的函數時,它會按照重整後的名字去目標檔案(.obj)中去尋找對應的函數,而目標檔案中存放的卻是C版本的函數,名字對不上,所以根本找不到!
怎麼辦呢?
這就是extern “C” 存在的一個原因了
它告訴C++,包含在extern “C”{ //…}塊中的東西是C版本的,你編譯的時候不要進行名字重整,否則你連結的時候就無法找到我!
於是上面的代碼也就不難理解了,光說不練是扯淡,上代碼
我們簡單的定義一個C標頭檔和實現檔案,只包含一個add函數
CClass.h 內容如下
#ifndef __CClass_H__ #define __CClass_H__ extern int add(int a, int b) ; #endif // end __CClass_H__ |
CClass.c 內容如下
#include "CClass.h" int add(int a, int b) { return a + b ; } |
下面我們用一個C++程式來引用這個C檔案
main.cpp 內容如下
#define _cplusplus // 為了測試,強加一句 #ifdef _cplusplus extern "C" { #endif #include "CClass.h" #ifdef _cplusplus } #endif #include <iostream> using namespace std ; int main(void) { int result = add(1, 2) ; cout << result << endl ; system("pause") ; return 0 ; } |
如果沒有#include <iostream>之前那些代碼而只是僅僅包含
#include "CClass.h"一句
你就會得到下面的錯誤
error LNK2019:unresolved external symbol "int __cdecl add(int,int)" (?add@@YAHHH@Z) referenced in function _main
顯然這是一個連結錯誤,因為找不到對應的函數定義
當然你也可以簡寫成下面的形式,直接在extern “C”塊中包含你想調用的函數
extern "C" { int add(int a, int b) ; }; #include <iostream> using namespace std ; int main(void) { int result = add(1, 2) ; cout << result << endl ; system("pause") ; return 0 ; } |
這在C++程式中是沒有問題的,但是如果是在C程式中,則會出現編譯錯誤,因為C中不允許extern “C”出現
另一個需要extern “C”的場合是當C程式調用C++的東西時
按照如下步驟做即可
1. 在C++的.h檔案中用extern “C”{}聲明將被C程式使用的函數
2. 在C++的.cpp檔案中實現上面的函數
3. 在.c檔案中用extern聲明要使用的C++函數
4. 使用即可
注意:切不可在.c檔案中包含C++的.h檔案,那樣編譯無法通過
上代碼:
CPPClass.h中聲明add函數
#ifndef __CPPClass_H__ #define __CPPClass_H__ extern "C" { int add(int a, int b) ; }; #endif // end __CPPClass_H__ |
CPPClass.cpp實現add函數
#include "CPPClass.h" int add(int a, int b) { return a + b ; } |
main.c 內容如下
#include <stdio.h> //#include "CPPClass.h" // 不要包含標頭檔,否則編譯不過 extern int add(int a, int b) ; // 只需顯示聲明要調用的函數即可 int main(void) { int result = add(1, 2) ; //使用函數 printf("%d", result) ; return 0 ; } |