一、extern的使用方法
下面是《C語言程序設計》中的關于extern的解釋:
在一個源程序的所有源文件中,一個外部變量只能在某個文件中定義一次,而其他文件可以通過extern聲明來訪問它(定義外部變量的源文件中也可以包含對該外部變量的extern聲明)。外部變量的定義中必須指定數組的長度,但extern聲明不一定指定數組的長度。
外部變量的初始化只能出現在其定義中。
假設函數push與pop定義在一個文件中,而變量val與sp在另一個文件中定義本那個被初始化(通常不太可能這樣組織程序),則需要通過下面這些定義與申明把這些函數與聲明“綁定”在一起:
在文件file1中:
extern int sp;
extern double val[];
void push(double f) {.......}
double pop(void) {........}
在文件file2中:
int sp=0;
double val[MAX_SIZE];
由于在file1中的extern申明不僅放在函數的外部,還放在它們的最前面,因此它們適用于該文件中的所有函數。對于file1,這樣一組聲明就夠了。如果要在同一文件中先使用、后定義變量sp與val,也需按照這種方式組織文件。
使用通俗的語言總結extern的使用方法,殼分為下面三種情況:
1) extern修飾變量的聲明。舉例來說,如果文件a.c需要引用b.c中變量int v,就可以在a.c中聲明extern int v,然后就可以引用變量v。這里需要注意的是,被引用的變量v的鏈接屬性必須是外鏈接(external)的,也就是說a.c要引用到v,不只是取決于在a.c中聲明extern int v,還取決于變量v本身是能夠被引用到的。這涉及到c語言的另外一個話題--變量的作用域。能夠被其他模塊以extern修飾符引用到的變量通常是全局變量。還有很重要的一點是,extern int v可以放在a.c中的任何地方,比如你可以在a.c中的函數fun定義的開頭處聲明extern int v,然后就可以引用到變量v了,只不過這樣只能在函數fun作用域中引用v罷了,這還是變量作用域的問題。對于這一點來說,很多人使用的時候都心存顧慮。好像extern聲明只能用于文件作用域似的。
2) extern修飾函數聲明。從本質上來講,變量和函數沒有區別。函數名是指向函數二進制塊開頭處的指針。如果文件a.c需要引用b.c中的函數,比如在b.c中原型是int fun(int mu),那么就可以在a.c中聲明extern int fun(int mu),然后就能使用fun來做任何事情。就像變量的聲明一樣,extern int fun(int mu)可以放在a.c中任何地方,而不一定非要放在a.c的文件作用域的范圍中。對其他模塊中函數的引用,最常用的方法是包含這些函數聲明的頭文件。使用extern和包含頭文件來引用函數有什么區別呢?extern的引用方式比包含頭文件要簡潔得多!extern的使用方法是直接了當的,想引用哪個函數就用extern聲明哪個函數。這大概是KISS原則的一種體現吧!這樣做的一個明顯的好處是,會加速程序的編譯(確切的說是預處理)的過程,節省時間。在大型C程序編譯過程中,這種差異是非常明顯的。
3) 此外,extern修飾符可用于指示C或者C++函數的調用規范。比如在C++中調用C庫函數,就需要在C++程序中用extern “C”聲明要引用的函數。這是給鏈接器用的,告訴鏈接器在鏈接的時候用C函數規范來鏈接。主要原因是C++和C程序編譯完成后在目標代碼中命名規則不同。這個用法的說明在下篇文章。
下面再歸納解釋一下extern的用法:
在C語言中,修飾符extern用在變量或者函數的聲明前,用來說明“此變量/函數是在別處定義的,要在此處引用”。
1. extern修飾變量的聲明。舉例來說,如果文件a.c需要引用b.c中變量int v,就可以在a.c中聲明extern int v,然后就可以引用變量v。這里需要注意的是,被引用的變量v的鏈接屬性必須是外鏈接(external)的,也就是說a.c要引用到v,不只是取決于在a.c中聲明extern int v,還取決于變量v本身是能夠被引用到的。這涉及到c語言的另外一個話題--變量的作用域。能夠被其他模塊以extern修飾符引用到的變量通常是全局變量。還有很重要的一點是,extern int v可以放在a.c中的任何地方,比如你可以在a.c中的函數fun定義的開頭處聲明extern int v,然后就可以引用到變量v了,只不過這樣只能在函數fun作用域中引用v罷了,這還是變量作用域的問題。對于這一點來說,很多人使用的時候都心存顧慮。好像extern聲明只能用于文件作用域似的。
2. extern修飾函數聲明。從本質上來講,變量和函數沒有區別。函數名是指向函數二進制塊開頭處的指針。如果文件a.c需要引用b.c中的函數,比如在b.c中原型是int fun(int mu),那么就可以在a.c中聲明extern int fun(int mu),然后就能使用fun來做任何事情。就像變量的聲明一樣,extern int fun(int mu)可以放在a.c中任何地方,而不一定非要放在a.c的文件作用域的范圍中。對其他模塊中函數的引用,最常用的方法是包含這些函數聲明的頭文件。使用extern和包含頭文件來引用函數有什么區別呢?extern的引用方式比包含頭文件要簡潔得多!extern的使用方法是直接了當的,想引用哪個函數就用extern聲明哪個函數。這大概是KISS原則的一種體現吧!這樣做的一個明顯的好處是,會加速程序的編譯(確切的說是預處理)的過程,節省時間。在大型C程序編譯過程中,這種差異是非常明顯的。
3. 此外,extern修飾符可用于指示C或者C++函數的調用規范。比如在C++中調用C庫函數,就需要在C++程序中用extern “C”聲明要引用的函數。這是給鏈接器用的,告訴鏈接器在鏈接的時候用C函數規范來鏈接。主要原因是C++和C程序編譯完成后在目標代碼中命名規則不同。
二、static的使用方法
下面是《C語言程序設計》中的關于static的解釋:
外部的static聲明通常多用于變量,當然,它也可用于聲明函數。通常情況下,函數名字是全局可訪問的,對整個程序的各個部分而言都可見。但是,如果把函數申明為static類型,則該函數名除了對該函數申明所在的文件可見外,其他文件都不可見。
static也可用于申明內部變量。static類型的內部變量同自動變量一樣,是某個特定函數的局部變量,只能在該函數中使用,但它與自動變量不同的是,不管其所在的函數是否別調用,它一直存在,而不像自動變量那樣,隨著所在函數的調用和退出而存在和消失。換句話說,static類型的內部變量是一種只能在某個特定函數中使用但一直占據空間的變量。
使用通俗的說法解釋關于static的三種用法:
1)在函數體,一個被聲明為靜態的變量在這一函數被調用過程中維持其值不變。這個變量也成為靜態局部變量。
2)在模塊內(但在函數體外),一個被聲明為靜態的變量可以被模塊內所用函數訪問,但不能被模塊外其它函數訪問。它是一個本地的靜態全局變量。
3)在模塊內,一個被聲明為靜態的函數只可被這一模塊內的其它函數調用。那就是,這個函數被限制在聲明它的模塊的本地范圍內使用。
三、typedef的使用方法
下面是《C語言程序設計》中的關于typedef的解釋:
從任何意義上上講,typedef申明并沒有創建一個新類型,它只是為某個已存在的類型增加了一個新的名稱而已。typedef聲明也沒有增加任何新的語義,通過這種方式聲明的變量和通過普通聲明方式聲明的具有完全相同的屬性。實際上,typedef類似于#define語句,但由于typedef是由編譯器解釋的,因此它的文本替換功能要超過處理器的能力。例如:
typedef int (*PFI)(char *, char * );
該語句定義了類型PFI是“一個指向函數的指針“,該函數具有兩個char*的參數,返回值類型為int *.
除了表達方式更簡潔之外,使用typedef還有另外的兩個重要原因。首先,它可以使程序參數化,以提高程序的可移植性。如果typedef聲明的數據類型同機器有關。那么,當程序移植到其他機器上時,只需要改變typedef類型定義即可。一個經常使用的情況,對于各種不同大小的整形來說,都使用通過typedef定義的類型名,然后,分別為各個不同的宿主機選擇一組合適的short 、int和long類型大小即可。標準庫中有一些例子,例如size_t和ptrdiff_t等。
四、const的使用方法
C語言中const代表著”不可變“,基本和常量一樣不可修改,但是應用場景不一樣。
1) 應用在變量
const char a='A';
a='B'; //錯誤,變量a的值不可以修改。
此時代表變量a值不可改變,任何企圖修改a變量值的語句(例如a=20;)都會報錯。
2) 應用在指針
應用在*左邊
const char *p;
char const *p;
以上兩條語句作用一樣,都是表示指針指向的變量值不可以修改,但指針可以修改。
例如1;
const char *p='A';
char *q;
*p='B'; //錯,指針指向的值不可以修改。
p=q; //對,指針值可以修改
應用在*右邊
char *const *p;
表示指針值(指針指向的位置)不可以改變,但指針指向的值可以改變。
例如2:
char *q;
*P='b'; // 對,指針指向的值可以修改。
p=q; //錯誤,指針值不可以修改。
3)應用在函數參數
例如3:strcat(char *a,char const *b),將參數b指向的字符串,添加到參數a字符串的末尾。
此時,參數*a值可以改變,但是表示參數*b值不可改變
新聞熱點
疑難解答
圖片精選