static、const、volatile等关键字作用
目錄
一、需要明白c語言中對象的一些屬性
1、C語言中內存分配
2、變量的作用域
3、鏈接屬性
4、存儲期
二、static、const、volatile關鍵字作用
1、static關鍵字作用
2、const關鍵字作用
3、volatile關鍵字作用
4、restrict
5、register
一、需要明白c語言中對象的一些屬性
在介紹關鍵字作用之前先聲明幾個概念
1、C語言中內存分配
C語言中內存分為5個區,分別為棧區,堆區,靜態存儲區,常量存儲區,代碼區。
1.1 棧區(stack): 由編譯器分配內存的區域,當編譯器需要的時候分配內存,使用完后清理內存,存放變量的類型為函數的形參、局部變量等。
1.2 堆區(heap): 指那些由程序員手動分配釋放的存儲區,如果程序員不釋放這塊內存,內存將一直被占用,直到程序運行結束由系統自動收回,c語言中使用malloc,free申請和釋放空間。
1.3 靜態存儲區(static): 靜態的概念是在程序執行過程中變量的地址不會發生改變。全局變量和局部靜態變量存放在這一塊區域,當程序結束后由系統釋放。其中初始化了的全局變量或者由static 修飾的全局或局部變量放在一個區域(DATA段),未初始化的全局變量放在BSS區。
1.4 常量存儲區:常量字符串就是儲存在這里的,儲存在常量區的變量為只讀變量。const修飾的全局變量也儲存在常量區,const修飾的局部變量依然在棧上。
1.5 程序代碼區:存放源程序的二進制代碼。
2、變量的作用域
一個C變量的作用域由4種:塊作用域,函數作用域,函數原型作用域,文件作用域。
2.1 塊作用域:塊是用一對花括號括起來的代碼區,例如函數是一個塊,函數中的復合語句也是一個塊。在塊內定義的變量具有塊作用域,塊作用域的可見范圍是從定義處到包含該定義的塊結束。如下面代碼示例1中,變量 a,num,i,p都是塊作用域。a的可見范圍為整個函數,函數外不可見,num可見范圍為從定義處到函數結束時結束,在for中也是有效的。i和p都是只在for循環中有效,在for循環的花括號后的函數區域p和i變量是不可見的。
//代碼示例1 void fun1(int a) {a++;int num=0;for(int i=0;i<3;i++){int p=i*a;num += p;}p=2; //錯誤,p不可見 }2.2 函數作用域:僅用于goto語句的標簽,使內層塊中的變量作用域為整個函數,避免在兩個塊中使用相同標簽發生混亂。
2.3 函數原型作用域: 作用域范圍是從形參定義處到函數原型處聲明結束。這樣函數定義和聲明中函數的形參名只需要保證變量類型一致即可,而形參名可以不同。
//函數聲明 int func(int a,int b);//函數形參可以與定義處不同...int main(void) {int q=0; q=func(2,3);//調用函數,返回5 return 0; }//函數定義 int func(int m,int f) {return m+f; }2.4 文件作用域:在函數外定義的變量具有文件作用域。從定義處開始到文件末尾均可見。
3、鏈接屬性
C變量種由3種鏈接屬性:外部鏈接,內部鏈接,無鏈接。
翻譯單元:一個c文件和它所包含的頭文件為一個翻譯單元。
3.1、無鏈接:具有塊作用域,函數作用域或函數原型作用域(局部變量,函數形參等)都是無鏈接變量,無鏈接只能在塊內可見。
3.2、內部鏈接:內部鏈接變量只能在一個翻譯單元內可見。
3.3、外部鏈接:具有外部鏈接的變量可以在多個c源文件中使用(不同翻譯單元都可使用),全局變量默認為外部鏈接,通過extern關鍵字在不同文件中引用。
4、存儲期
C語言中對象有4種存儲期:靜態存儲期、線程存儲期、自動存儲期、動態存儲期。
4.1、 靜態存儲期:如果對象具有靜態存儲期,那么它在程序執行期間一直存在。文件作用域變量就具有靜態存儲期。
4.2、線程存儲期:用于并發程序中,如果對象具有線程存儲期,那么該對象從聲明到線程結束中一直存在。程序的執行可以被分為多個線程,多個線程交替運行使人感覺多個程序同時運行。
4.3、自動存儲期:塊作用域具有自動存儲期,當編譯器使用到這些塊時為它們分配內存,當塊結束時清理掉這一部分內存,這一部分內存是可以反復使用的,自動存儲期的變量一般保存在內存的棧中。
4.4、動態存儲期:由程序員手動申請和釋放的變量。如使用malloc()申請內存,free()釋放內存,注意:free()只是將申請的內存收回到系統中,但是指針本身指向的地址并沒有發生改變,所以釋放地址后一般需要將指針的值改變(如指向NULL)。如果申請內存后不釋放,該內存到程序結束前一直被占用,可能會造成大量內存浪費。
| 變量類別 | 存儲期 | 作用域 | 鏈接 | 聲明方式 | 
| 普通局部變量 | 自動 | 塊 | 無 | 在塊內聲明 | 
| 靜態局部變量 | 靜態 | 塊 | 無 | 在塊內用static聲明 | 
| 全局變量(外) | 靜態 | 文件 | 外部 | 在所有函數外聲明 | 
| 全局變量(內) | 靜態 | 文件 | 內部 | 函數外用static聲明 | 
| 寄存器 | 自動 | 塊 | 無 | 在塊內用register聲明 | 
二、static、const、volatile關鍵字作用
1、static關鍵字作用
1.1對于局部變量
使用static關鍵字修飾局部變量,會改變變量的存儲期,由自動存儲期改為靜態存儲期。由程序開始時就分配內存并且初始化(如果程序沒有顯示的初始化,系統會默認初始化為0),當后面調用函數或塊時不會再進行初始化,在程序結束時由系統清理內存。
1.2對于全局變量
使用static關鍵字修飾全局變量,會改變變量的鏈接屬性,由外部鏈接改為內部鏈接,在其他c文件中該變量是不可見的。全局變量默認為外部鏈接,在不同的c源文件可以通過extern來使用相同的變量,但是當使用static修飾全局變量后,變為內部鏈接這樣不同的翻譯單元就不能使用到同一個變量,但是不同的翻譯單元可以使用同一個變量名(變量名相同,并不意味著是同一個對象)。如下代碼,在file1.c和file2.c中兩個a不是同一個變量,但是兩個f1為同一個變量。
//file1.h //int b=0;//當兩個c文件引用頭文件存在這種代碼,系統會提示錯誤,原因是同一個變量對象被聲明了兩次 static int a=0;//這樣是能編譯通過的,因為在兩個c文件中雖然都有了a變量,但他們只是在各種的翻譯單元中有效,相互之間沒有關系 int fun2(void);//聲明file2中定義的函數,在file1.c中可以使用 //file1.c #include<stdio.h> #include"file1.h" int f1=7;//這個變量在file2.c中可以用 extern int f1;來聲明該變量在其他文件中已經聲明,來操作該變量 static f2=0;// 這個變量不能通過上訴操作來找到,因為它是內部鏈接 int main(void) { printf("file1中a的地址為:%p\n",&a); printf("file1中f1的地址為:%p,f1=%d \n",&f1,f1);fun2();return 0;}//file2.c #include<stdio.h> #include"file1.h" extern int f1;//聲明在其他文件中已經定義,注意在這里只能引用示聲明,不能賦值。 int fun2(void) {printf("file2中a的地址為:%p\n",&a); printf("file2中f1的地址為:%p,f1=%d \n",&f1,f1); return 0;}/*輸出結果 file1中a的地址為:00007FF6953D9BB0 file1中f1的地址為:00007FF6953DC00C,f1=7 file2中a的地址為:00007FF6953D9BB4 file2中f1的地址為:00007FF6953DC00C,f1=7*/1.3對于函數
當有static修飾函數時該函數的作用域也變成了僅在本翻譯單元可見。在其他c文件中不能引用該函數,即使在頭文件同聲明也不行。沒有static聲明的函數在上一個代碼示例中,在不同的c文件中可以引用。
//file2.h static int fun3(int a,int b);//file2.c ... static int fun3(int a,int b) { return a+b; } ... //file3.c #include "file2.h" void quate() { int a=0; a=fun3(1,1);//會報錯,該函數沒有定義,因為static修飾的函數其他翻譯單元不可見 }2、const關鍵字作用
const會讓變量成為只讀變量,初始化過后其值不能通過賦值,遞增,遞減來修改。一般用來對需要保護的數據使用如:int fun(const int arr[]){};避免在fun函數中修改arr數組的值。
const int a=0; a=2;//不允許修改 const int arr[2]={1,2};//創建不允許修改的數組 //const修飾指針 int b=0; int c=1; const int *p1 = &b; int const* p2 = &b;//const 在*前為常量指針,即指針指向一個常量,即 *p為常量,p為變量 *p1=2;//不能通過解引用方式修改,*p1是不可修改的左值 b=2;//可以直接修改變量 p1=&c;//可以修改指針指向的地址 int * const p2 = &b;//const在 * 后為指針常量,即該指針為一個常量,不能修改指向的地址,即 p為常量但是*p是變量 *p2=3;//可以修改指針指向內容的值 p2=&c;//不能修改指向的地址 const int * const p2 = &b;//指針的值和指向的地址都不能改變3、volatile關鍵字作用
由volatile聲明的變量不應該優化,告訴計算機該變量是可以改變的,每次讀寫該變量時都需要在變量內存地址中操作,而不應該優化在寄存器中。
volatile語法和const一樣.
4、restrict
restrict聲明的變量是允許編譯器優化,提升程序的效率。它只能用于指針,表明該指針是訪問某一數據對象的唯一且初始的方式。
5、register
用register修飾的變量,該變量保存在寄存器中,讀寫速度塊,但是不能獲取該變量的地址。
總結
以上是生活随笔為你收集整理的static、const、volatile等关键字作用的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 基于决策树的高层次语义图像检索
- 下一篇: 纯生js ajax,纯生js实现Elem
