C語言關鍵字auto與register及static專項詳解
1.auto
在解釋 auto 之前,先來了解一下什么是局部變量。
在很多印象中,對局部變量的描述是:函數(shù)內(nèi)定義的變量稱為局部變量。并且下面這段代碼也很好的解釋了這句話:
#include <stdio.h> void print() { int a = 10; printf("%d", a); } int main() { print(); printf("%d", a); return 0; }
顯然這段代碼是錯的,編譯器也會報錯:
但事實上 “函數(shù)內(nèi)部定義的變量是局部變量” 這種說法是不錯的,但是不準確。我們來看這樣一段代碼:
#include <stdio.h> int main() { int func = 10; if (func) { int num = 1; } printf("%d", num); return 0; }
同樣編譯器也會報錯:
所以正確的理解應該是:在 { } 中定義的變量叫做局部變量。
那么我們順水推舟提一個問題:局部變量與我們的關鍵字 auto 有什么聯(lián)系?
其實在早期的C語言中,局部變量是需要用 auto 修飾的,但現(xiàn)在的編譯器發(fā)展越來越智能,會自動識別哪個變量是局部變量。所以,現(xiàn)在對于局部變量的 auto 關鍵字都是省略的。
我們可用這段代碼證明:
#include <stdio.h> void print() { auto int a = 10; printf("%d\n", a); } int main() { int a = 10; printf("%d\n", a); print(); return 0; }
所以對于 auto 這個關鍵字來說,只需了解、知道就好。
2.register
千萬不能把這個單詞翻譯成:登記、注冊!正確的翻譯應該是:寄存器。
那寄存器是什么?寄存器是計算機 CPU 的一組硬件,存在的本質是提高計算機的運行效率,因為寄存器不需要從內(nèi)存中拿數(shù)據(jù)。也就是說把數(shù)據(jù)直接放在寄存器,直接供 CPU 計算,從而提升運行效率。
所以我們大膽猜測:register 修飾的變量,意義在于盡量把修飾的變量放入 CPU 寄存器中。
那么什么樣的變量適合用 register 來修飾呢?
- 局部變量(全局變量會長時間占用寄存器)
- 不會被寫入的變量(因為一旦寫入將會寫回內(nèi)存,register 就沒有意義了)
- 被高頻使用的變量
我們通過代碼來闡述如何使用這個關鍵字:
#include <stdio.h> int main() { register num = 10; int sum = 0; int i = 0; for (i = 0; i < 10; i++) { sum += num+i; } printf("%d\n", sum); return 0; }
這段代碼完美符合了適合使用 register 修飾的變量的三個條件,雖然規(guī)模又億些小,算法有億些簡單。num 變量是局部變量,并且接下來的代碼沒有對其進行寫入,并且重復使用了 10 次。
如果我們寫了 200000 個局部變量,并且所有的局部變量都用 register 來修飾,那么編譯器會不會因為寄存器不夠用而報錯?我認為不會,因為 register 的定義是盡量把變量放入寄存器中。
3.static
對于 static 這個關鍵字,一般應用于多文件操作中,這是因為有利于項目維護、提供安全保證。
那么對于多文件操作不是本篇的內(nèi)容,我會在另外一篇單獨寫一篇關于這塊的內(nèi)容。
那么 stactic 可以修飾的對象有三個:
- 全局變量
- 函數(shù)
- 局部變量
我們先觀察全局變量沒有被 static 修飾的時候的效果:
我們在 test.c 文件中定義全局變量:
//test.c int num = 10;
在 test.h 文件中對此聲明:
//test.h #pragram once #include <stdio.h> extern int num;
在 main.c 文件中使用此變量:
//main.c #include "test.h" int main() { printf("%d\n", num); return 0; }
運行結果:
現(xiàn)在我們來觀察當全局變量被 static 修飾的時候會發(fā)生什么:
在 test.c 下使用 static 修飾全局變量,其他文件不變:
//test.c static int num = 10;
運行結果:
可以看到這個程序在鏈接時出現(xiàn)了錯誤,即 num 變量“消失”了一樣。那么這種“消失”恰恰是 static 的魅力所在。
結論一:對于 static 修飾的全局變量,該變量就變?yōu)橹荒茉诒疚募惺褂茫荒鼙黄渌募苯邮褂谩?/p>
但是要注意,僅僅是不能被直接使用,我們通過間接訪問,程序還是可以運行的:
我們在 test.c 中定義一個函數(shù):
//test.c #include "test.h" static int num = 10; void print() { printf("%d\n", num); }
test.h 文件中聲明 print 函數(shù):
//test.h #pragma once #include <stdio.h> extern int num; void print();
在 main.c 文件中我們這樣做:
//main.c #include "test.h" int main() { //printf("%d\n", num); print(); return 0; }
那么運行的效果:
上面這種情況我們可以把它視為 static 沒有修飾 print 函數(shù)的情況。所以現(xiàn)在我們來討論 static 修飾函數(shù)時候的情況:
在 test.c 文件中修飾 print 函數(shù):
//test.c #include "test.h" int num = 10; static void print() { printf("%d\n", num); }
test.h 、main.c 文件不變,運行結果為:
可以看到函數(shù)被 static 修飾的效果與 全局變量變量被 static 修飾的時候一致,那么我們不難得出下面的結論:
結論二:當 static 修飾函數(shù)時,此函數(shù)只能在本文件內(nèi)使用,不能被其他文件直接訪問。
同理,我們可以修改代碼來達到間接訪問:
我們在 test.c 中多寫一個函數(shù):
//test.c #include "test.h" int num = 10; static void print() { printf("%d\n", num); } void func() { print(); }
在 test.h 中對此函數(shù)進行聲明:
//test.h #pragma once #include <stdio.h> extern int num; void print(); void func();
在 main.c 中調用:
//main.c #include "test.h" int main() { //printf("%d\n", num); //print(); func(); return 0; }
運行結果:
現(xiàn)在,我們觀察局部變量沒有被 static 修飾的時候的一段代碼:
#include <stdio.h> void test() { int i = 0; i++; printf("%d\n", i); } int main() { for (int i = 0; i < 10; i++) { test(); } return 0; }
那么它的輸出結果是:
很明顯,超出了我們的預期。我們的預期是輸出 1,2,3,4,5,6,7,8,9,10 。為什么輸出 10 次輸出的都是 1 呢?對于局部變量來說,生命周期在 { } 中定義開始,在出 { } 時結束。也就是說,在 { } 中定義的局部變量在內(nèi)存中開辟了一塊空間,在出 { } 時開辟的空間釋放(銷毀)。
那有什么辦法能使空間不被釋放呢?有,那就是用 static 修飾局部變量:
#include <stdio.h> void test() { static int i = 0; i++; printf("%d\n", i); } int main() { for (int i = 0; i < 10; i++) { test(); } return 0; }
輸出的結果是:
那么為什么會輸出這樣的結果呢?從上面的結果分析我們知道了局部變量的生命周期,我們只要改變局部變量的生命周期就能夠解決問題。也就是說,static 修飾的局部變量,能夠讓其原本儲存在棧區(qū)而讓其存儲到靜態(tài)區(qū),只能被定義一次(對于任何變量來說都是這樣,只不過我們的重點在于改變變量的生命周期)從而達到修改生命周期的作用。
結論三:static 修飾局部變量,能夠讓其生命周期從局部周期變?yōu)槿种芷凇?/p>
到此這篇關于C語言關鍵字auto與register及static專項詳解的文章就介紹到這了,更多相關C語言 auto register static內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!