extern關鍵字

微笑吐舌頭extern關鍵字會提升變量或者函數的逼格,使得它們可以跨文件被訪問。話雖然是這麼說,使用這個關鍵字必須要注意一些東西。

微笑吐舌頭首先,你得在cpp文件裏面實現這些全局變量和全局函數,這是最基本的,然後只需要在需要用到這些變量和函數的文件裏聲明一下,用extern修飾聲明,這樣弄完之後就可以隨意使用這些全局變量和全局函數了。請不要爲編譯器擔心,擔心它們找不到這些東西,只要你實現了,不怕編譯器找不到。

微笑吐舌頭別的文件裏寫一堆的extern聲明顯得特別不專業,也顯得代碼十分臃腫,有沒有好的做法呢?有的。

微笑吐舌頭我們一般把所有的全局變量和全局函數都放在一個*.cpp文件裏面,然後用一個同名的*.h文件包含所有的函數和變量的聲明。用法的示例如下:

  1. /*Demo.h*/  
  2. #ifndef _DEMO_H_  
  3. #define _DEMO_H_  
  4.   
  5. extern int a;  
  6. extern int b;  
  7. int add(int a, int b);  
  8.   
  9. #endif  
  10. /** 
  11. //下面的寫法也可以 
  12. #pragma  once 
  13. extern int a; 
  14. extern int b; 
  15. */  
  1. /*Demo.cpp*/  
  2. #include "Demo.h"   
  3. int a = 10;  
  4. int b = 20;  
  5.   
  6.  int add(int l, int r)  
  7. {  
  8.     return l + r;  
  9. }  
  1. /*main.cpp*/  
  2. #include "Demo.h"  
  3. #include <iostream>  
  4. using namespace std;  
  5.   
  6. void main()  
  7. {  
  8.     cout << "a = " << a << ", b = " << b << endl;  
  9.   
  10.     int c = add(1, 2);  
  11.     printf("c = 1 + 2 = %d \n", c);  
  12.     system("pause");  
  13. }  

生氣生氣運行結果如下:


生氣生氣這樣處理之後只需要到用到的地方加入#include"Demo.h"一句即可,很方便吧!這麼幹方便了這些變量和全局函數的管理。

生氣生氣下面是關於extern關鍵字的一些說明:

微笑吐舌頭(1)extern聲明外部函數

生氣生氣在A.cpp中使用B.cpp中的函數,需要extern聲明。定義的形式類似於:

extern  int  a;

生氣生氣這裏需要注意定義和聲明的區別,extern  int  a = 10;屬於定義了。

  1. /*Demo.h*/  
  2. #ifndef _DEMO_H_  
  3. #define _DEMO_H_  
  4.   
  5. extern int a = 10;  
  6. extern int b = 20;  
  7. int add(int a, int b);  
  8.   
  9. #endif  
  10. /** 
  11. //下面的寫法也可以 
  12. #pragma  once 
  13. extern int a; 
  14. extern int b; 
  15. */  
  1. /*Demo.cpp*/  
  2. #include "Demo.h"  
  3. int a = 10;  
  4. int b = 20;  
  5.   
  6.  int add(int l, int r)  
  7. {  
  8.     return l + r;  
  9. }  
  1. /*main.cpp*/  
  2. #include "Demo.h"  
  3. #include <iostream>  
  4. using namespace std;  
  5.   
  6. void main()  
  7. {  
  8.     cout << "a = " << a << ", b = " << b << endl;  
  9.   
  10.     int c = add(1, 2);  
  11.     printf("c = 1 + 2 = %d \n", c);  
  12.     system("pause");  
  13. }  

難過委屈這麼幹肯定是編譯不通過的,因爲存在重定義,#include"Demo.h"這一句是單純的代碼替換,在Demo.cpp和main.cpp裏替換之後你自然發現全局變量被定義了兩次,肯定會報錯。一句話,聲明可以拷貝n次,但是定義只能定義一次

 

微笑吐舌頭(2)extern聲明全局變量

難過委屈在A.cpp中使用B.cpp中的全局變量,需要extern聲明。

難過委屈extern關鍵字的作用是告訴編譯器,在某個cpp文件中,存在這麼一個函數/全局變量。

安靜鄙視函數的聲明類似於:

extern  int  sum(int, int);

難過委屈函數的聲明語句中,關鍵字extern可以省略,因爲全局函數默認是extern類型的,因此也就出現了Demo.h中的狀況。

 

難過委屈雖然用extern聲明瞭變量和函數之後,在別的文件裏就隨意使用了,但是你也千萬別忘了書寫變量和函數的實現,否則就會出現無法解析的外部符號,編譯無法通過。

鄙視鄙視還有一件很有趣的事情,如果你將前面的Demo.cpp改爲Demo.c的話,編譯器會告訴你說找不到變量和函數是無法解析的外部符號,怎麼辦呢?

大笑吐舌頭之所以會出現這樣的原因,是因爲c++編譯器和c編譯器差異性的問題,C++語言在編譯的時候爲了解決函數的多態問題,會將函數名和參數聯合起來生成一箇中間的函數名稱,而C語言則不會,因此會造成鏈接時找不到對應函數的情況,我們是在main.cpp文件裏包含了Demo.h也就是在main.cpp裏面聲明瞭這麼一些變量和函數(代入即可),main.cpp裏面的聲明會被c++編譯器成處理中間的名稱,而Demo.c裏面的實現會被c編譯器處理,兩者處理的差異性(詳情可以看我後面提供的鏈接),導致問題多多。總之處理之後.c文件的實現和.cpp裏面的聲明不一致了,這也是導致找不到的原因,這個時候就必須用extren "C"了,告訴c++編譯器,請保持我的名稱,不要給我生成用於鏈接的中間函數名。

鄙視鄙視我們將Demo.h裏面的東西改一下寫法即可:

  1. /*Demo.h*/  
  2. #ifndef _DEMO_H_  
  3. #define _DEMO_H_  
  4.   
  5. #ifdef  __cplusplus  
  6. extern "C" {  
  7. #endif  
  8.   
  9.     extern int a;  
  10.     extern int b;  
  11.     int add(int a, int b);  
  12.   
  13.   
  14. #ifdef  __cplusplus  
  15. }  
  16. #endif  
  17.   
  18. #endif  
  1. /*Demo.c*/  
  2. //#include "Demo.h"  
  3. #include <stdio.h>  
  4. int a = 10;  
  5. int b = 20;  
  6.   
  7.  int add(int l, int r)  
  8. {  
  9. #ifndef __cplusplus  
  10.     printf("這是一個c程序!\n");  
  11. #endif // !_cplusplus  
  12.   
  13. #ifdef __cplusplus  
  14.     printf("這是一個c++程序!\n");  
  15. #endif // !_cplusplus  
  16.     return l + r;  
  17. }  
  1. /*main.cpp*/  
  2. #include "Demo.h"  
  3. #include <iostream>  
  4. using namespace std;  
  5.   
  6. void main()  
  7. {  
  8. #ifdef __cplusplus  
  9.     cout << "這是一個c++程序" << endl;  
  10. #endif  
  11.   
  12. #ifndef __cplusplus  
  13.     cout << "這是一個c程序" << endl;  
  14. #endif  
  15.     cout << "a = " << a << ", b = " << b << endl;  
  16.   
  17.     int c = add(1, 2);  
  18.     printf("c = 1 + 2 = %d \n", c);  
  19.     system("pause");  
  20. }  

再見再見運行結果如上圖,特別要聲明一下__cplusplus,前面是兩個_,在.c文件沒有定義__cpluspluscpp文件定義了__cplusplus,一不小心將__cplusplus寫成了_cplusplus會出現什麼呢?就是我下面的情況了。

  1. /*Demo.h*/  
  2. #ifndef _DEMO_H_  
  3. #define _DEMO_H_  
  4.   
  5. #ifndef  _cplusplus  
  6. extern "C" {  
  7. #endif  
  8.   
  9.     extern int a;  
  10.     extern int b;  
  11.     int add(int a, int b);  
  12.   
  13.   
  14. #ifndef  _cplusplus  
  15. }  
  16. #endif  
  17.   
  18. #endif  
  1. /*Demo.c*/  
  2. //#include "Demo.h"  
  3. #include <stdio.h>  
  4. int a = 10;  
  5. int b = 20;  
  6.   
  7.  int add(int l, int r)  
  8. {  
  9. #ifndef _cplusplus  
  10.     printf("這是一個c程序!\n");  
  11. #endif // !_cplusplus  
  12.   
  13. #ifdef _cplusplus  
  14.     printf("這是一個c++程序!\n");  
  15. #endif // !_cplusplus  
  16.     return l + r;  
  17. }  
  1. /*main.cpp*/  
  2. #include "Demo.h"  
  3. #include <iostream>  
  4. using namespace std;  
  5.   
  6. void main()  
  7. {  
  8. #ifdef _cplusplus  
  9.     cout << "這是一個c++程序" << endl;  
  10. #endif  
  11.   
  12. #ifndef _cplusplus  
  13.     cout << "這是一個c程序" << endl;  
  14. #endif  
  15.     cout << "a = " << a << ", b = " << b << endl;  
  16.   
  17.     int c = add(1, 2);  
  18.     printf("c = 1 + 2 = %d \n", c);  
  19.     system("pause");  
  20. }  

再見再見說實話,結果我挺震驚的,在Demo.c文件中定義的函數跑出一個“這是一個c程序”,也沒什麼,在一個cpp文件中的函數跑出一個“這是一個c程序”,我就很震驚了,原因我也不清楚,不過基本就是上面的解決方案了,最後說一下不在Demo.c包含#include"Demo.h"的原因,因爲在extern “C”不是爲C所支持,其實也不算吧!

再見再見因爲網上說.c文件沒有定義_cplusplus而cpp文件定義了_cplusplus,如果真是這樣在Demo.c包含#include"Demo.h"也不會出現問題,可是不知道是我的編譯器原因還是什麼的,c文件和cpp文件都沒定義_cplusplus,因此有可能Demo.c包含#include"Demo.h"出現問題,因爲爲了能在cpp文件中使用,Demo.h文件裏我一般要寫成#ifndef_cplusplus,此時若Demo.c包含#include"Demo.h",恰好c文件中也沒有定義_cplusplus,那麼extern “C”就暴露出來了,自然會錯。


再見再見ps:關於extern和extern “C”,有更好的講解,我就不班門弄斧了。

再見再見鏈接:http://pan.baidu.com/s/1o6CACga 密碼:xefl


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章