前言
不知道有人是否在意過C中的extern 這個關(guān)鍵字,又或者說是否使用過該關(guān)鍵字,當(dāng)學(xué)C++時候,我發(fā)現(xiàn)了在C++中有關(guān)鍵字 extern"C" 的用法,和C語言中的 extern 還是有區(qū)別的,所以今天來總結(jié)一些對他們的理解,和使用的方式。
extern 關(guān)鍵字的用法很簡單,就是簡簡單單的聲明,它可以明確的指出一個語句是聲明; 比如extern int i ;那么就說明 這是聲明變量 i,而不是定義i,聲明是不開辟內(nèi)存的,定義是開辟內(nèi)存的。 假如int i ;沒有extern 修飾,那就說明為定義,會分配內(nèi)存空間的。
extern 的使用場景1
extern 可以聲明一個變量,使得該變量是來自其他文件的變量在本文件可以被訪問。
比如:創(chuàng)建兩個文件 test.c 和 main.c文件; 在test.c文件中定義一個全局變量:
//test.c
int i = 20; //定義一個全局變量
在main.c文件,聲明變量 i;
main.c文件
# include<stdio.h>
extern int i; //聲明變量i,當(dāng)編譯鏈接時候,main.c文件就可以訪問到test.c文件的i的值了;
int main()
{
printf("%d",i);
return 0;
}
這樣我們就可以跨文件(test.c),在本文件(main.c)訪問這個變量了;
extern 的使用場景2
但是上訴的使用方式并不好,假如我一個大工程,這個工程由超級多的文件,這些文件假如都要訪問 test.c 文件的 變量 i,那么,只能在這些文件中,每個文件的開頭都 聲明變量 i,并且,假如我的test.c ,不止一個定義一個變量i,有好多其他變量呢?在其他文件訪問時候,都要聲明好多變量,這會使得書寫難度很繁瑣,并且維護(hù)成本也大;
所以一般,我們都把聲明語句放到頭文件使用,即我定義一個test.h 的頭文件; 在該頭文件中,聲明 extern int i ; 然后,假如你在其他文件要使用改變量i,直接包含該頭文件即可, 比如:test.h 頭文件
//test.h 頭文件
extern int i;
extern int j;
extern int k;
//...
//聲明很多很多變量
在其他.c文件,只要包含該頭文件,就可以啦,比如在main.c 文件:
# include<stdio.h>
# include"test.h"
//extern int i; 不用寫了
//extern int j;不用寫了
//extern int k;不用寫了
//...
//聲明很多很多變量,都不用寫了,因?yàn)榘祟^文件,聲明都在頭文件中
int main()
{
printf("%d %d %d",i,j,k);
return 0;
}
extern的用法總結(jié)
extern一般用于聲明,在.h文件中,聲明變量或者函數(shù)(函數(shù)可以不加extern,但是最好加上,這樣比較統(tǒng)一);在其他文件要訪問該變量函數(shù)時候,包含頭文件就行哦。
二. extern “C” 的理解和用法
在C++中,extern"C"修飾的語句是按照C語言的方式進(jìn)行編譯的。
怎么理解這句話呢?
我來舉幾個例子:(理解它extern"C"的含義) 我們知道在C++中函數(shù)是可以發(fā)生重載的,即編譯的時候并不會報錯,在C語言中,是沒有重載的說法的;那么假如我用extern"C"去修飾重載的函數(shù)的話,即在編譯時候,就會按照C語言的方式去編譯了: 這個時候,就會發(fā)生錯誤; 看例子:創(chuàng)建一個main.cpp文件
# include<iostream>
using namespace std;
extern "C" void func() //用 extern"C"修飾
{
}
extern "C" void func(int v)//用 extern"C"修飾
{
{
}
int main()
{
return 0;
}
看下面的報錯信息,不允許重載啊,本來我C++文件就是可以重載的,但是用extern“C”修飾過后,就不可重載函數(shù)了,這就是按照C的編譯方式編譯,假如按C++編譯方式編譯那就是能通過的。
extern"C" 也是可以修飾聲明函數(shù)的,也說明該函數(shù)時按照C語言的方式編譯; extern"C" 也是可以用大括號{ } 的方式聲明函數(shù)的; 如下例子:
extern "C" void func(); //用 extern"C"修飾聲明函數(shù)
extern "C" void func(int v);//用 extern"C"修飾聲明函數(shù)
//上訴例子會報錯,C語言編譯沒有重載啊。
///
///
///
extern "C" { //修飾函數(shù)聲明
void func();
void func(int v);
} //用大括號的方式一起寫進(jìn)來,也是可以。
//上訴例子會報錯,C語言編譯沒有重載啊。
///
///
///
extern "C" { //修飾函數(shù)定義
void func()
{
}
void func(int v)
{
}
} //用大括號的方式一起寫進(jìn)來,也是可以。
//上訴例子會報錯,C語言編譯沒有重載啊。
但是可以使用大括號的方式使用extern“C”,這是正確的
看看下面的例子:
# include<iostream>
using namespace std;
extern "C" void func() //用 extern"C"修飾
{
}
void func(int v) //這個不用extern“C”聲明
{
}
int main()
{
return 0;
}
上面的情況不會報錯,原因很簡單:extern "C" void func() { } 按C語言方式編譯,這個不會錯;void func(int v){ } 按C++方式編譯,所以也不會報錯,這兩者雖然函數(shù)名字相同,但是他們時按照不同的編譯方式編譯的,所以不報錯;
extern"C "使用 在C與C++混合開發(fā)中的使用方式
通常在C++ 中,假如需要使用C語言中的庫文件的話,可以使用extern "C"去包含;
那如何使用呢?接下來我一步一步帶你理解如何使用,先舉幾個例子。
比如:創(chuàng)建math.c(C文件)中,有一些函數(shù)是數(shù)學(xué)的加法和減法功能函數(shù)。 我想在main.cpp文件中使用math.c文件中的函數(shù),如何使用呢? 第一種辦法:在main.cpp文件用extern"C"包含math.c文件中的你想用的函數(shù)。
//math.c文件
int add (int x,int y)//加法
{
return x+y;
}
int sub(int x,int y)//減法
{
return x-y;
}
int mult(int x,int y)//乘法
{
return x*y;
}
int div(int x,int y) //除法
{
return x/y;
}
main.cpp(C++文件)中,要使用math.c文件中的函數(shù).
//main.cpp文件
#include<iostream>
using namespace std;
extern “C” //用extern“C”{ }聲明math.c文件中的函數(shù),以至于可以在main.cpp文件使用。
{
int add (int x,int y);
int sub(int x,int y);
}
int main()
{
cout<<add(10,20)<<endl; //由于有聲明該函數(shù),所以訪問成功,結(jié)果30
cout<<sub(10,20)<<endl;//由于有聲明該函數(shù),所以訪問成功,結(jié)果-10
return 0;
}
第二種使用方式:
假如我有一個需求,我想在main.cpp文件,用math.c文件中的其他函數(shù),比如除法函數(shù),乘法函數(shù); 那么我就只能在 main.cpp 中 extern"C"{ }的括號中,逐個的加上這兩個函數(shù);這好像也可以正常使用沒問題,但是,這很麻煩啊,別人使用你的.c庫時候會先得非常麻煩。所以我們一般使用頭文件的方式,即創(chuàng)建多一個頭文件math.h,在math.h里聲明函數(shù),在math.c文件定義函數(shù),在main.cpp,即要使用該庫文件里面,用extern"C"{ } ,在括號里包含該math.h頭文件即可
看下math.h頭文件內(nèi)容:
// math.h文件的內(nèi)容
int add (int x,int y);//加法
int sub(int x,int y);//減法
int mult(int x,int y);//乘法
int div(int x,int y); //除法
在math.c中定義函數(shù)
//math.c文件
int add (int x,int y)//加法
{
return x+y;
}
int sub(int x,int y)//減法
{
return x-y;
}
int mult(int x,int y)//乘法
{
return x*y;
}
int div(int x,int y) //除法
{
return x/y;
}
這時候我們只要在main.cpp文件中,用extern “C”{ }包含該頭文件就可以使用了。
//main.cpp文件
#include<iostream>
using namespace std;
extern"C"{ //包含頭文件,該里面是C語言方式編譯的。
# include"math.h"
}
int main()
{
cout<<add(10,20)<<endl; //由于有聲明該函數(shù),所以訪問成功,結(jié)果30
cout<<sub(10,20)<<endl;//由于有聲明該函數(shù),所以訪問成功,結(jié)果-10
cout<<mutl(10,20)<<endl;
cout<<div(10,20)<<endl;
return 0;
}
這樣就可以正常使用了。
但是,上面的使用方式還是不太好,該方式還是有一定的問題,什么問題呢?就是我在main.cpp文件使用extern "C"{ #include"math.h"} ,即要多寫一個 extern"C"{ } ,顯得格外麻煩,再說了,假如還有其他Cpp文件要用這個C語言的庫呢。都是這種方式,extern"C" 太麻煩啦 。我們之前都是直接#include"math.h" ,這樣才是我們平時的使用習(xí)慣呢。
所以有了這第三種使用方式:(為的是直接在main.cpp中,#include"math.h"就可以使用,不用多謝extern"C")
直接在math.h 中,用extern"C" 的方式修飾就行啦。那么我就可以在main.cpp 直接#include"math.h" 。 (代碼就不寫啦,文字可以理解就行)
上面的使用有并不是完全好的方式,如何說呢?假如我有一個.c 文件,創(chuàng)建為other.c ,我這個文件呢,也想使用math.c 的函數(shù),那么我就可以在other.c 文件直接包含該math.c 文件就可以了,可是事實(shí)卻不如所想,這樣會報錯,報錯的原因是,由于在math.h 文件中,聲明函數(shù)用了extern"C" ,而other.c文件# include"math.h" ,會包含里面的所有內(nèi)容,包括里面的 extern"C" , 這個extern"C" 在other.c 文件,即C語言文件是不認(rèn)識extern"C" 啊,所以會報錯
下面展示報錯的代碼,創(chuàng)建other.c 文件(C文件),里面包含math.h 文件(該文件有extern"C"{ } 聲明方式 )
//other.c文件
# include"math.h"
//包含頭文件,由于這是.c文件,不是.cpp文件。所以.c文件不認(rèn)識extern"C",所以會報錯
void test()
{
int ret = add(10,20);//報錯,不認(rèn)識,add.
}
所以如何解決上面問題呢? 核心問題是,我希望有一種使用 extern"C"的方式,在C語言文件中,能夠使用該庫,在C++文件中也可以使用該庫。
要解決這個問題: 也是 第四種使用方式
由于編譯器默認(rèn)會在,你創(chuàng)建的任何一個.cpp文件中,默認(rèn)定義一個宏 #define __cplusplus ,這個宏是你看不到的,是編譯器默認(rèn)給每個.cpp文件創(chuàng)建的,而在.c文件,即C語言的編譯器,是沒有這個宏的,所以我們可以借助它,來在 math.h文件中使用下面的代碼:
看math.h的代碼
// math.h文件的內(nèi)容
//意思是如果使用該頭文件math.h的文件定義了__cplusplus,
//則下面代碼到#endif都是有效的,在這里是 extern "C" { 有效
#ifdef __cplusplus
extern "C" {
#endif //__cplusplus
int add (int x,int y);//加法
int sub(int x,int y);//減法
int mult(int x,int y);//乘法
int div(int x,int y); //除法
//意思是如果使用該頭文件math.h的文件定義了__cplusplus,
//則下面代碼到#endif都是有效的,在這里是 } 有效
#ifdef __cplusplus
}
#endif //__cplusplus
在main.cpp文件你直接包含該頭文件math.h就可以使用了; 在other.c文件中你直接包含該頭文件math.h就可以使用了;
只要按上面的方式書寫,那么就可以完美的解決了在C文件和C++文件中混用的問題;你既可以在.c文件使用該頭文件,也可以在.cpp文件中使用該文件庫。
第四種方式是最值得推薦的。
三. 總結(jié)
兩者 extern 和 extern"C"有點(diǎn)區(qū)別:
- extren 在C和C++中,都表示聲明語句的意思;
- 而 extern"C"是按C語言方式去編譯文件;
- extern"C"只能在C++文件使用,extern在C和C++都可以使用;
|