extern "C"的簡單解析


1.揭密extern "C"

extern "C"包含雙重含義,從字面上即可得到:首先,被它修飾的目標是 "extern”的;其次,被它修飾的目標是 "C”的。
首先來看一下 "extern”的含義
a.在一個文件內,如果外部變量不在文件的開頭定義,其有效范圍只限定在定義到文件的結束處。如果在定義前需要引用該變量,則要在引用之前用關鍵字 "extern” 對該變量做“外部變量聲明”,表示該變量是一個已經定義的外部變量。有個這個聲明,就可以從聲明處起合理地使用該變量了。"extern”起到了擴展作用域的作用。

//.c
#include <stdio.h>
void main()
{
    extern A;//用extern聲明外部變量;若變量為int類型,類型名可寫也可以省略。
    printf("%d", A);
}
int A=100;

b.在多文件的程序中,如果多個文件都要使用同一個外部變量,不能在各個文件中各定義一個外部變量,否則會出現“重復定義”的錯誤。正確的做法是:在任一個文件中定義外部變量,其他文件用 "extern”對變量做“外部變量聲明”。在編譯和連接時,系統會由此知道該變量是一個已經在別處定義的外部變量,並把另一文件中外部變量的作用域擴展到本文件,這樣在本文件就可以合法地使用該外部變量了。

//file1.c
#include <stdio.h>
int A = 100;//定義外部變量
void main()
{
    printf("%d",power());
}

//file2.c
extern A;//聲明A為一個已定義的外部變量
int power()
{
    return A*A;
}

extern只用作聲明,而不用於定義。extern說明變量或者函數定義在其他的源文件里,而不用include頭文件的方式來引用該函數,在鏈接時,鏈接器在各個模塊中搜索這個變量或者函數來進行最終鏈接。
c.外部函數
在定義函數時,如果在最左端加關鍵字extern,表示此函數是外部函數。C語言規定,如果在定義時省略extern,則隱含為外部函數。而內部函數必須前加static關鍵字;
在需要調用此函數的文件中,用extern對函數作聲明,表示該函數是在其他文件中定義的外部函數。
"C”的含義:(extern “C”)
C++通過函數參數的不同類型支持重載機制,編譯器根據參數為每個重載函數產生不同的內部標識符。例如編譯器為void Eat(Beef …);void Eat(Fish …);void Eat(Chicken …);三個Eat 函數產生象_eat_beef、_eat_fish、_eat_chicken 之類的內部標識符(不同的編譯器可能產生不同風格的內部標識符)。
如果 C++程序要調用已經被編譯后的C 函數,該怎么辦?
假設某個 C 函數的聲明如下:

void foo(int x, int y);

該函數被C 編譯器編譯后在庫中的名字為_foo,而C++編譯器則會產生像_foo_int_int之類的名字用來支持函數重載和類型安全連接。由於編譯后的名字不同,C++程序不能直接調用C 函數。C++提供了一個C連接交換指定符號extern“C”來解決這個問題。
例如:

extern “C”
{
void foo(int x, int y);
… // 其它函數
}
或者寫成
extern “C”
{
#include “myheader.h”
… // 其它C 頭文件
}

這就告訴C++編譯譯器,函數foo 是個C 連接,應該到庫中找名字_foo 而不是找_foo_int_int。C++編譯器開發商已經對C 標准庫的頭文件作了extern“C”處理,所以我們可以用#include 直接引用這些頭文件。

2.extern "C"程序實例

假設有C文件:

//c.h
#ifndef _C_H_
#define _C_H_

extern int add(int x, int y);

#endif
//c.c
int add(int x, int y)
{
    return x+y;
}

在C++下調用add()函數

//cplusplus.cpp
#include <iostream>
#include "c.h"
using namespace std;
void main()
{
    add(1, 0);
    system("Pause");
}

產生錯誤:無法解析的外部符號 "int __cdecl add(int,int)" (?add@@YAHHH@Z),該符號在函數 _main 中被引用
為了解決這個問題,我們需要使用extern "C"。改寫C文件

//c.h
#ifndef _C_H_
#define _C_H_

#ifdef __cplusplus
extern "C" {
#endif

extern int add(int x, int y);

#ifdef __cplusplus
}
#endif

#endif

文件為*.c,__cplusplus沒有被定義,extern "C" {}這時沒有生效,對於C語言只是extern int add(int, int);而編譯c++源文件,__cplusplus被定義,對於C++他看到的是extern "C" {extern int add(int, int);},編譯器就會知道add(1, 0)調用的是C連接。
最后:很多DLL的生成文件(XXX.c)中常出現extern "C" ,windows采用C語言編譯創建dll,C程序可以正確調用DLL,而當用戶使用C++調用DLL時,extern "C" {}就起作用了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM