相對於其他語言來說,C語言的關鍵字算是少的了。在C98中關鍵子總共只有32個,我們來分析一下每個關鍵字在C語言中它獨特的作用。
1、關於數據類型的關鍵字
(1) char :聲明字符型變量或函數
(2) double :聲明雙精度變量或函數
(3) enum :聲明枚舉類型
enum類型可以增加可讀性,可移植性;在enum中定義的每個對象,默認都是從0開始,當然也可以自定義。如下:
enum Color{RED,BLACK,WHITE};
enum Number{ONE=1,TWO,THREE};
Color中RED=0,BLACK=1,WHITE=2;
Number中ONE=1,TWO=2,THREE=3;
(4) float:聲明浮點型變量或函數
(5) int: 聲明整型變量或函數
(6) long :聲明長整型變量或函數
(7) short :聲明短整型變量或函數
(8) signed:聲明有符號類型變量或函數
(9) struct:聲明結構體變量或函數
結構體struct的作用已經在上一篇博文中講到,可以用來實現C語言的封裝,繼承,多態等等。
請參考http://www.cnblogs.com/whc-uestc/p/4677414.html
(10) union:聲明共用體(聯合)數據類型
union類型可以用來提高內存的使用率,如下:
復制代碼
int main(){
union Unoin{int a;float b;char *c;};
union Unoin p;
p.a = 100;
/*
執行語句1
*/
p.b = 10.0;
/*
執行語句2
*/
p.c = "hello world!";
/*
執行語句3
*/
return 0;
}
復制代碼
如果不使用union,我們需要分別定義int,float,cahr*,需要占用12字節的內存空間,但是當我們使用union時,只需要占用4字節即可;但是需要注意的時,我們在上面那個代碼中執行語句2或者3中需要用到int a時,就無法使用union了,必須單獨定義int a;否則讀出的a值將會錯誤的。
(11) unsigned:聲明無符號類型變量或函數
(12) void :聲明函數無返回值或無參數,聲明無類型指針(基本上就這三個作用)
2、關於控制語句的關鍵字
循環語句
(13) for:一種循環語句(可意會不可言傳)
(14) do :循環語句的循環體
(15) while :循環語句的循環條件
條件判斷語句
(16)if: 條件語句
(17)else :條件語句否定分支(與 if 連用)
(18)switch :用於開關語句
(19)case:開關語句分支
(20)default:開關語句中的“其他”分支
在case...switch語句中,當一個條件輸入,從滿足條件的那個case語句開始執行,直到遇到跳轉指令(break;return;goto;contine;),所以建議在每條case語句後面加上break,除非你是刻意不那麼做的。
跳轉語句
(21)goto:無條件跳轉語句
用goto語句可以保證程序存在唯一的出口,避免了過於龐大的if嵌套,但是隨意使用goto語句就會對程序帶來很大的隱患(可能會跳過變量的初始化、重要的計算語句等),影響代碼的健壯性和可讀性。所以不推薦過多地使用。
(22) continue:結束當前循環,開始下一輪循環
(23) break:跳出當前循環
(24)return :子程序返回語句(可以帶參數,也可以不帶參數)
在return語句之後函數中的所有指令都不會執行,所以需要確保在return語句之前執行完必要的指令。
3、關於存儲類型的關鍵字
(25)auto :聲明自動變量 一般不使用,因為當我們聲明一個局部變量是默認就是auto
(26)extern:聲明變量是在其他文件正聲明(也可以看做是引用變量),一般也需要經常使用,因為在C語言裡面,全局變量和函數都是默認extern的屬性
(27)register:聲明寄存器變量,聲明為register的變量是存放在CPU的寄存器裡面的,所以讀取速度非常快,但是數量有限,當定義的多個register變量,編譯器多的那些register變量轉換為auto變量。
(28)static :聲明靜態變量
a、當我們把一個全局變量聲明為static時:只有它的作用范圍變為本源文件,也就是屬性由external變為internal,其它不變;
b、當我們把函數聲明為static時:它的作用范圍變為本源文件,也就是屬性由external變為internal;
c、當我們把局部變量聲明為static時:默認初始化值為0,並且只在第一次定義時初始化;內存存儲區域不再是棧,而是在靜態存儲區;生命周期不再是所在函數,而是整個進程;其它不變。
4、其它一些關鍵字
(29)const :聲明只讀變量
由const聲明的變量,必須在定義時進行初始化。如下:
const int num = 10;//在定義處初始化,並且變量的值不允許再改變
既然變量的值都不允許改變,那麼這個變量定義了有啥用?哈哈,用處大著呢。首先在我們定義數組的時候,數組的大小就可以用const定義的常量來表示,這個就跟#define一樣,但是它是類型安全的,#define是預處理命令,只是進行簡單的字符替換,而編譯器會對const定義的變量進行類型檢查;其次,當我們需要一個不再改變的變量時,就可以用const,比如說定義一個人的性別,自打你一出生就已經決定了你的性別,不出意外的話,這輩子都不會改變了,所以就把它定義為只讀的,當然有人也認為不定義為const也可以的嘛,只要自己不改變它就行,但是如果是那樣的話,就需要人為來控制了,萬一哪天忘了,把它改了怎麼辦?所以對於一些只讀或者常量最好用const來定義。
當我們把const與指針變量放在一起的時候,問題就變得復雜了。比如我們定義如下:
const int *p1;
int const *p2;
int * const p3;
int const * const p4;
指針變量p1:const在數據類型之前,修飾的是p1所指向的對象,所以p1所指向的對象的值為常量只讀,不能改變,但是p1本身可以改變;
指針變量p2:const在*之前,這種情況與p1相同;
指針變量p3:const在*之後,修飾的是變量p3,所以變量p3本身為常量只讀,而p3所指向的對象可以改變;
指針變量p4:有兩個const分別修飾變量p4和p4所指向的對象,所以p4本身和p4所指向的對象都為常量只讀,都不可以改變。
其實這些也很容易記住,只要看const是在*前還是在*後面,在*前修飾的就是指針所指向的對象,在*後,修飾的就是指針本身。
下面來舉個簡單的例子說明:
復制代碼
int main(){
int num1 = 0;
int num2 = 1;
int num3 = 2;
int num4 = 3;
const int *p1;
int const *p2;
//int * const p3; //error(1)
int * const p3 = &num3;
//int const * const p4; //error(2)
int const * const p4 = &num4;
p1 = &num1;
//*p1 = 100;//error(3)
num1 = 100;//此時*p = 1;
//p3 = p4;//error(4)
*p3 = 100;
//p4 = p3;//error(5)
return 0;
}
復制代碼
在上面代碼中,error(1)和error(2)很容易理解,因為const在*之後,所以指針p3,p4本身為只讀,在定義時必須初始化。error(3)是因為對於p1指針,const在*之前,所以p1所指向的對象不能改變。error(4)和error(5)是因為對於p3,p4,有const在*之後,所以指針本身只讀,在初始化之後,就無法再改變了。
(30)sizeof:計算數據類型長度
很多人不理解sizeof與strlen的區別:sizeof是運算符,而strlen是函數;sizeof計算的是數據類型的大小,而strlen計算的是字符串的長度;sizeof的參數既可以是數據類型,也可以是變量,而strlen的參數只能是char*,而且必須是空字符結尾;sizeof返回值類型為unsigned,而strlen返回值為signed,因為它需要返回負數來表示出錯情況。
(31)typedef:用以給數據類型取別名
typedef在程序設計裡面很有用,當一個數據類型很長時(比如說函數指針),我們就可以用typedef來選用一個很合適的名字來替代它;當我們使用int,float,double這些類型時,也可以使用自己喜歡並且直觀的名字來重新定義它,這樣,當我們以後需要把項目中的float類型換成double類型的時候,我們就可以直接在typedef上把float換成double就可以,而不需要把所有代碼裡面每個float換成double。
(32)volatile:說明變量在程序執行中可被隱含地改變
volatile 修飾的變量不允許編譯器對與它有關的運算做任何優化;用volatile定義的變量可能會在程序外被改變,所以每次都必須從內存中讀取,而不能把他放在cache或寄存器中重復使用。一般用在以下幾個地方:
a、並行設備的硬件寄存器(如:狀態寄存器)
b、一個中斷服務子程序中會訪問到的非自動變量(Non-automatic variables)
c、多線程應用中被幾個任務共享的變量
以上結論只是個人的見解與建議,如果上述所說有誤或者大家有不同的見解,歡迎指正與討論。