1. 程式人生 > >c語言中定義變數的幾個關鍵字

c語言中定義變數的幾個關鍵字

1.auto
(1)auto關鍵字在C語言中只有一個作用,那就是修飾區域性變數。
(2)auto修飾區域性變數,表示這個區域性變數是自動區域性變數,自動區域性變數分配在棧上。(既然在棧上,說明它如果不初始化那麼值就是隨機的······)
(3)平時定義區域性變數時就是定義的auto的,只是省略了auto關鍵字而已。可見,auto的區域性變數其實就是預設定義的普通的區域性變數。

2.static
(1)static關鍵字在C語言中有3種用法,而且這兩種用法彼此沒有任何關聯、完全是獨立的。其實當年本應該多發明一個關鍵字,但是C語言的作者覺得關鍵字太多不好,於是給static增加了一種用法,導致static一個關鍵字竟然有兩種截然不同的含義。
(2)static的第一種用法是:用來修飾區域性變數,形成靜態區域性變數。要搞清楚靜態區域性變數和非靜態區域性變數的區別。本質區別是儲存類不同(儲存類不同就衍生出很多不同):非靜態區域性變數分配在棧上,而靜態區域性變數分配在資料段/bss段上。
(3)static的第二種用法是:用來修飾全域性變數,形成靜態全域性變數。要搞清楚靜態全域性變數和非靜態全域性變數的區別。區別是在連結屬性上不同:靜態全域性變數的連線屬性是檔案內連線;非靜態全域性變數的連線屬性是檔案外連線。

(3)static的第二種用法是:用來修飾函式,將函式的作用域限制在本檔案中,其他檔案不可見。
分析:

   static的後兩種作用本質是一樣的,都是將全域性變數或函式限制在本檔案中。
    靜態區域性變數在儲存類方面和全域性變數一樣,都是在資料段或bss段。
    靜態區域性變數在生命週期方面和全域性變數一樣,從程式開始到程式消亡。
    靜態區域性變數和全域性變數的區別是:作用域、連線屬性。靜態區域性變數作用域是程式碼塊作用域(和普通區域性變數是一樣的)、      連結屬性是無連線;全域性變數作用域是檔案作用域(和函式是一樣的)、連結屬性方面是外連線。

3.register
(1)register關鍵字不常用,也只有一個作用,那就是:register修飾的變數。編譯器會盡量將它分配在暫存器中。(平時分配的一般的變數都是在記憶體中的)。分配在暫存器中一樣的用,但是讀寫效率會高很多。所以register修飾的變數用在那種變數被反覆高頻率的使用,通過改善這個變數的訪問效率可以極大的提升程式執行效率時。所以register是一種極致提升程式執行效率的手段。
(2)uboot中用到了一個register型別的變數,gd這個變數是用來存uboot的全域性變數(gd就是global data)。因為這個全域性變數在整個uboot中到處都被訪問,所以定義成register的。
(3)平時寫程式碼要被定義成register這種情況很少,一般慎用。
(4)register編譯器只能承諾儘量將register修飾的變數放在暫存器中,但是不保證一定放在暫存器中。主要原因是因為暫存器數量有限,不一定有空用。

4.extern
(1)extern主要用來宣告全域性變數,宣告的目的主要是在a.c中定義全域性變數而在b.c中使用該變數。
(2)C語言中程式的編譯時以單個.c原始檔為單位的,因此編譯a.c時只考慮a.c中的內容(不會考了b.c的內容),這就導致a.c中使用了b.c中定義的變數時在編譯時報錯。解決方案是宣告
(3)應該在a.c中使用g_b之前先宣告g_b,宣告就是告訴a.c我在別的檔案中定義了g_b,並且它的原型和宣告的一樣,將來在連結的時候連結器會在別的.o檔案中找到這個同名變數。宣告一個全域性變數就要用到extern關鍵字

5.volatile
(1)volatile的字面意思:可變的、易變的。C語言中volatile用來修飾一個變數,表示這個變數可以被編譯器之外的東西改變。編譯器之內的意思是變數的值的改變是程式碼的作用,編譯器之外的改變就是這個改變不是程式碼造成的,或者不是當前程式碼造成的,編譯器在編譯當前程式碼時無法預知。譬如在中斷處理程式isr中更改了這個變數的值,譬如多執行緒中在別的執行緒更改了這個變數的值,譬如硬體自動更改了這個變數的值(一般這個變數是一個暫存器的值)
(2)以上說的三種情況(中斷isr中引用的變數,多執行緒中共用的變數,硬體會更改的變數)都是編譯器在編譯時無法預知的更改,此時應用使用volatile告訴編譯器這個變數屬於這種(可變的、易變的)情況。編譯器在遇到volatile修飾的變數時就不會對改變數的訪問進行優化,就不會出現錯誤。
(3)編譯器的優化在一般情況下非常好,可以幫助提升程式效率。但是在特殊情況(volatile)下,變數會被編譯器想象之外的力量所改變,此時如果編譯器沒有意識到而去優化則就會造成優化錯誤,優化錯誤就會帶來執行時錯誤。而且這種錯誤很難被發現。
(4)volatile是程式設計師意識到需要volatile然後在定義變數時加上volatile,如果你遇到了應該加volatile的情況而沒有加程式可能會被錯誤的優化。如果在不應該加volatile而加了的情況程式不會出錯只是會降低效率。所以我們對於volatile的態度應該是:正確區分,該加的時候加不該加的時候不加,如果不能確定該不該加為了保險起見就加上。

6.restrict
(1)c99中才支援的,所以很多延續c89的編譯器是不支援restrict關鍵字,gcc支援的。
(2)restrict也是和編譯器行為特徵有關的。
(3)restrict只用來修飾指標,不能修飾普通變數。
(4)http://blog.chinaunix.net/uid-22197900-id-359209.html