深入理解extern用法

2021-07-03 16:45:32 字數 3213 閱讀 8133

我們一般把所有的全域性變數和全域性函式的實現都放在乙個*.cpp檔案裡面,然後用乙個同名的*.h檔案包含所有的函式和變數的宣告。如:

/*demo.h*/

#pragma once

extern inta;

extern intb;

intadd(inta,intb);

/*demo.cpp*/

#include "demo.h" /*這句話寫或者不寫在本例中都行,不過建議不寫*/

/*不寫不會出問題,寫了有些情況下會出問題,下面有解釋*/

int a =10;

int b =20;

int add(intl,intr)

如果將demo.cpp寫成了demo.c,編譯器會告訴你說無法解析的外部符號。

因為demo.c裡面的實現會被c編譯器處理,然而c++和c編譯器在編譯函式時存在差異,所以會存在找不到函式的情況。

extern

int a; //屬於宣告  extern

int a = 10; //屬於定義,同下

externcharg_str="123456";//

這個時候相當於沒有

extern

如果在乙個檔案裡定義了char g_str = "123456";在另外乙個檔案中必須使用extern char g_str[ ];來宣告。不能使用extern char* g_str;來宣告。extern是嚴格的宣告。且extern char* g_str只是宣告的乙個全域性字元指標。

注:宣告可以拷貝

n次,但是定義只能定義一次。

被extern "c"限定的函式或變數是extern型別的:

extern是c/c++語言中表明函式和全域性變數作用範圍(可見性)的關鍵字,該關鍵字告訴編譯器,其宣告的函式和變數可以在本模組或其它模組中使用。記住,下列語句:

extern int a;

僅僅是乙個變數的宣告,其並不是在定義變數a,並未為a分配記憶體空間。變數a在所有模組中作為一種全域性變數只能被定義一次,否則會出現連線錯誤。

通常,在模組的標頭檔案中對本模組提供給其它模組引用的函式和全域性變數以關鍵字extern宣告。例如,如果模組b欲引用該模組a中定義的全域性變數和函式時只需包含模組a的標頭檔案即可。這樣,模組b中呼叫模組a中的函式時,在編譯階段,模組b雖然找不到該函式,但是並不會報錯;它會在連線階段中從模組a編譯生成的目標**中找到此函式。

與extern對應的關鍵字是static,被它修飾的全域性變數和函式只能在本模組中使用。因此,乙個函式或變數只可能被本模組使用時,其不可能被extern 「c」修飾。

實現c++與c及其它語言的混合程式設計:

被extern"c"修飾的變數和函式是按照c語言方式編譯和連線的,未加extern 「c」則按照宣告時的編譯方式。

(1)在c++中引用c語言中的函式和變數,在包含c語言標頭檔案(假設為cexample.h)時,需進行下列處理:

extern "c"

而在c語言的標頭檔案中,對其外部函式只能指定為extern型別,c語言中不支援extern"c"宣告,在.c檔案中包含了extern"c"時會出現編譯語法錯誤。

(2)在c中引用c++語言中的函式和變數時,c++的標頭檔案需新增extern"c",但是在c語言中不能直接引用宣告了extern"c"的該標頭檔案,應該僅將c檔案中將c++中定義的extern"c"函式宣告為extern型別。

(1)extern表明該變數在別的地方已經定義過了,在這裡要使用那個變數。

(2)static 表示靜態的變數,分配記憶體的時候,儲存在靜態區,不儲存在棧上面。

static作用範圍是內部連線的關係這和extern有點相反。它和物件本身是分開儲存的,extern也是分開儲存的,但是extern可以被其他的物件用extern引用,而static不可以,只允許物件本身用它。具體差別首先,static與extern是一對「水火不容」的傢伙,也就是說extern和static不能同時修飾乙個變數;其次,static修飾的全域性變數宣告與定義同時進行,也就是說當你在標頭檔案中使用static宣告了全域性變數後,它也同時被定義了;最後,static修飾全域性變數的作用域只能是本身的編譯單元,也就是說它的「全域性」只對本編譯單元有效,其他編譯單元則看不到它,如:

/*test1.h*/

#ifndef test1h

#define test1h

static char g_str="123456";

void fun1();

#endif

/*test1.cpp*/

#include "test1.h"

void fun1()

這個時候你在跟蹤**時,就會發現兩個編譯單元中的g_str位址並不相同,因為你在一處修改了它,所以編譯器被強行的恢復記憶體的原貌,在記憶體中存在了兩份拷貝給兩個模組中的變數使用。正是因為static有以上的特性,所以一般定義static全域性變數時,都把它放在原檔案中而不是標頭檔案,這樣就不會給其他模組造成不必要的資訊汙染,同樣記住這個原則吧!

c++中const修飾的全域性常量具有跟static相同的特性,即它們只能作用於本編譯模組中,且static修飾的是全域性變數,但是const可以與extern連用來宣告該常量可以作用於其他編譯模組中,如extern

const char g_str;

然後在原檔案中別忘了定義:const char g_str = "123456";

所以當const單獨使用時它就與static相同,而當與extern一起合作的時候,它的特性就跟extern的一樣了!所以對const我沒有什麼可以過多的描述,我只是想提醒你,const char* g_str = "123456" 與 const char g_str ="123465"是不同的,前面那個const修飾的是char *而不是g_str,它的g_str並不是常量,它被看做是乙個定義了的全域性變數(可以被其他編譯單元使用), 所以如果你像讓char* g_str遵守const的全域性常量的規則,最好這麼定義const char* const g_str="123456"。

深入理解Lambda函式及其用法

1.函式式程式設計 例如 乙個整數列表,要求按照列表中元素的絕對值大小公升序排列 list1 3,5,4,1,0,2,6 sorted list1,key lambda x abs x 0,1,2,3,4,5,6 排序函式sorted支援接收乙個函式作為引數,該引數作為 sorted的排序依據,這裡...

深入理解公式 1,0 的用法

一 從右往走進行vlookup 查詢kt002叫什麼名字 公式 vlookup kt002 if h 7 h 10,g 7 g 10 2,false 公式解釋 二 多條件查詢 根據 郭靖男 查詢出對應的年齡 公式 vlookup 郭靖男 if g7 g10 i7 i10,j7 j10 2,false...

深入理解Lambda函式及其用法

lambda函式又稱匿名函式,匿名函式就是沒有名字的函式,函式沒有名字也行?當然可以啦。有些函式如果只是臨時一用,而且它的業務邏輯也很簡單時,就沒必要非給它取個名字不可。先來看個簡單lambda函式 lambda x,y x y lambda at 0x102bc1c80 x和y是函式的兩個引數,冒...