--事物的難度遠遠低於對事物的恐懼!
這章來聊聊變數的屬性,玩過遊戲的朋友都知道,遊戲裡各個角色都有各自特定的屬性,才有了各個角色的功力不同,這個只能打小妖而那個卻能戰大怪,這就因為它們具有不同的屬性。
而在c語言中,變數也可以有自己的屬性,屬性不同,變數的在程式中具有的特性也不同。那麼如何給變數加上自己的屬性?很簡單:在定義變數的時候加上"屬性"關鍵字,這個"屬性"關鍵字就指明了變數的特殊意義,語法如下:
proterty(屬性關鍵字) type(型別名) var_name(變數名);
所以我們就可以這樣給變數加上屬性
auto int i; //i的屬性為auto
register int j; //i的屬性為register
static long l; //i的屬性為static
extern double d; //i的屬性為extern
c語言中有那麼多的屬性關鍵字,它們分別使得變數具有什麼特別的意義?下邊我們來逐一分析分析:
auto屬性關鍵字:
-auto是c語言中區域性變數的預設屬性(注意是區域性變數)
-auto屬性,表明將其修飾的變數儲存於棧上(想想上一點說的區域性變數,存在**?)
-編譯器預設所有的區域性變數的屬性都為auto(auto英文的意思,就是自動,所以屬性名還是起的很貼心的)
基於以上三點,我們就知道,下邊**中的兩個變數i跟j的屬性,是一致的:
void fun(void)
register屬性關鍵字:-register關鍵字指明將區域性變數盡量儲存於暫存器中(注意是區域性變數,因為全域性變數的生命週期為整個程式的生命週期,假如全域性變數能宣告為register變數,那麼就會一直占用著這個暫存器,而cpu的暫存器就那麼點,所以乾脆就不允許宣告全域性變數為register變數)
-register只是請求暫存器變數,但不一定請求成功(這點很容易理解,乙個cpu就那麼點暫存器,怎麼可能將所有的變數都宣告為暫存器變數)
-register變數必須是cpu暫存器可以接受的值(好吧,這好像是廢話。。。)
-不能用&取址符獲取register變數的位址(我們日常所說的取變數的位址,是**的位址?肯定是變數在記憶體裡的位址嘛,暫存器又不是記憶體,怎麼能取址?)
來看下邊這個例子
#include register int i; //error,i為全域性變數,不能用register關鍵字修飾
int main()
既然register有那麼多的使用限制,那麼register屬性關鍵字到底有什麼用?
答案是:效率!效率!效率!因為cpu是直接讀取暫存器的,所以將變數放在暫存器中,cpu的操作速度會相當快,而要操作記憶體中的變數,那麼就會先把記憶體的中變數放到暫存器中,cpu再從暫存器中讀取,記憶體到cpu中間會有乙個橋梁過度。
static關鍵字:
-static關鍵字修飾的變數具有"靜態"屬性
-static修飾的區域性變數儲存在程式靜態區(即原來儲存在棧中,轉換到儲存到靜態區中),生命週期與全域性變數一樣。
-static關鍵字也具有"作用域限定符"的意義
-被static修飾的全域性變數或函式,它們的作用域僅僅是在宣告的檔案中
下邊來個例子感受一下static關鍵字:
#include int g_v; //全域性變數,程式的任意地方均能訪問
static int g_vs; //靜態全域性變數,僅僅能在當前宣告的檔案中訪問
int main()
對於以上說的auto、register、static三個關鍵字,下邊用乙個程式來做個對比:
#include int f1()
int f2()
void fun(void)
int main()
for(i=0; i<5; i++)
return 0;
}
輸出結果如下:
我們來分析下輸出結果
首先看變數i與變數k的位址值,程式中我們定義的兩個變數是相鄰的,而從輸出的位址值可以很明顯看到,二者在記憶體中儲存的位置絕對不是相鄰或相近的,為什麼?因為我們把i定義成普通區域性變數,k定義為靜態區域性變數,二者在記憶體中的儲存位置是不一樣的,所以輸出的位址值,肯定不會相鄰的,這樣問題就很明顯了。
這麼說也許還不夠,那我們再來做驗證,把修飾變數k的static關鍵字去掉,讓k與i具有一樣的屬性,均為普通區域性變數,再來看看二者的位址輸出值(**修改很簡單,這裡就直接貼上輸出結果),結果已經很明顯,i跟k在記憶體中的位置,已經是相鄰近了。
現在我們來分析兩個for語句的輸出,也很簡單,因為f1()中的變數r是普通區域性變數,作用域也僅僅在f1()函式中,所以每次迴圈f1()函式執行完,其裡邊的變數r就消亡了,下次迴圈,r就重新定義,所以第乙個for迴圈每次輸出的值,都是重新定義的;再來看看第二個for迴圈,因為f2()中的變數r定義為static靜態變數,所以生命週期與全域性變數一樣,為整個程式的生命週期,這樣每次迴圈,就會在上一次迴圈的基礎上遞增,所以就會有我們的輸出。
extern關鍵字:
1. extern關鍵字用於宣告"外部"定義的變數和函式
-extern變數在檔案的其他地方分配空間
-extern函式在檔案的其他地方定義
2. extern用於"告訴"編譯器用c的方式編譯
-c++編譯器和一些類c編譯器缺省會以自己的方式編譯函式和變數,通過extern關鍵字可以命令編譯器"以標準c方式進行編譯",下邊這段**,就會以標準c的方式進行編譯
extern "c"
};
下邊用**來演示,extern關鍵字如何使用,我們定義兩個檔案,main.c與test.c內容分別為
檔案
#include extern int i;
extern int geti();
int main()
檔案
int i = 10;
int geti()
輸出:
很明顯,當編譯器編譯到main.c中的i變數時,發現i變數使用extern關鍵字宣告,這時編譯器就知道,i變數是在其他地方定義了,於是編譯器就到工程中的其他地方找,於是在test.c中找到了,同理函式int geti()也一樣。
思考個問題:假如把test.c中的int i = 10,變為static int i = 10; 或者int geti()變為static int geti()程式還能編譯通過嗎?為什麼?
總結:1、auto變數儲存在程式的棧中,是預設屬性
2、static變數儲存在程式的靜態資料區中
3、register變數請求儲存於cpu的暫存器中,請求不一定成功
4、extern變數在檔案的其他地方分配空間
5、extern能夠指示編譯器按照標準c的方式編譯程式
C語言變數屬性
在c語言中,變數是具有屬性的,主要有auto static register extern auto 區域性變數的自動預設屬性,不需要顯示宣告,且儲存在棧上 register 暫存器變數,請求編譯器將區域性變數儲存在暫存器中,由於是請求,編譯器有可能拒絕,所以儘管利用register對變數進行了修飾...
C語言中的變數
開場白要吸引人.但是我不會 有人說我可以靠臉吃飯。可我偏偏選擇了手,哈哈哈 說笑 娛樂娛樂,下面我就來提提c語言中關於變數的意思 什麼是變數?沒錯 你看字面意思就可以理解,就是可以變得量,用專業一點的話就是程式中其值可以變化的量。變數有三個基本要素 變數名 每乙個變數都應該有乙個名字。變數的資料型別...
C語言中的變數
一.普通區域性變數 區域性變數無論是否靜態均不允許同名,否則會出現error 當區域性變數與全域性變數同名時,依據就近原則進行判斷。區域性變數同名是指在復合語句的巢狀中,內層復合語句變數與外層復合語句變數同名,這樣是允許的。二.普通全域性變數 全域性變數無論是否靜態都不允許同名,否則編譯器會給出er...