1. 程式人生 > >深入理解C之關鍵字

深入理解C之關鍵字

        由於最近一段時間一直在忙於WEB的前端開發,很久都沒有寫過C方面的程式,感覺很陌生了一樣,真的是一天不練,都被拉到千里之外,趁現在正好手上有一個關於C方面的專案,特地的總結了一下C語言關鍵字的使用及注意事項。

                          C語言標準定義的32個關鍵字

auto 宣告自動變數,預設時編譯器一般預設為auto
int 宣告整理變數
double 宣告雙精度變數
long 宣告長整型變數
char 宣告字元型變數
float 宣告單精度浮點變數
short 宣告短整型變數
signed 宣告有符號型別變數
unsigned 宣告無符號型別變數
struct 宣告結構體變數
union 宣告聯合資料型別
enum 宣告列舉型別
static 宣告靜態變數
switch 用於開關語句
case 開關語句分支
default 開關語句的其它分支
break 跳出當前迴圈
register 宣告暫存器變數
const 宣告只讀變數
volatile 說明變數在程式執行中可被隱含地改變
typedef 用以給資料型別取別名
extern 宣告變數是在其他檔案中宣告(也可看作引用變數)
return 子程式返回語句(可以帶引數,也可以不帶引數)
void 宣告函式無返回值或無引數、宣告空型別指標
continue 結束當前迴圈,開始下一輪迴圈
do 迴圈語句的迴圈條件
while 迴圈語句的迴圈條件
if 條件語句
else 條件語句否定分支
for 一種迴圈語句(可意會不可言傳)
goto 無條件跳轉語句
sizeof 計算物件所佔記憶體空間大小

      下面挑選一些比較重要,容易將用法和概念混淆的關鍵字進行總結,以下內容是本人查詢資料進行整理的。

一、Const

      const從字面是恆定不變的意思,也翻譯成常量和常數,可能正因為這一點,很多人都認為被const修飾的值是常量,這不精確,精確來說應該是隻讀變數,其值在編譯時不能被使用。

      1、Const作用

             (1)可以定義定義const常量:const int MAX = 100;
             (2)便於進行型別檢查:const常量有資料型別,而巨集常量沒有資料型別,

             (3)可以保護被修飾的東西:防止意外的修改,增強程式的健壯性。

             (4)可以很方便的進行引數的調整:同巨集定義一樣,可以做到不變則已,一變都變。

             (5)提高了效率:編譯器通常不為普通const常量分配儲存空間,而是將它們儲存在符號表中。

             示例程式:

             #define   M      3                     //巨集常量

             const  int  N = 5;                   //此時並未將N放入記憶體中

             .......

             int  i = N;                                //此時為N分配記憶體,以後不再分配

             int  I = M;                               //預編譯期間進行巨集替換,分配記憶體

             int  j = N;                                //沒有記憶體分配

             int  J = M;                               //再進行巨集替換,又一次分配記憶體

       2、Const的變數和指標使用

         (1)定義常量:const修飾型別的變數value是不可變的,以下兩種定義形式在本質上是一樣的。

            int const ValueName = value;

            const int ValueName = value;

        (2)指標使用const

            a. 指標本身是常量不可變

                     char* const pContent;

           b. 指標所指向的內容是常量不可變

                     char const* pContent;

           c. 兩者都不可變

                     const char* const pContent;

           d. 區別方法

                   在*中間畫一條線,如const在*左邊,則const修飾指向的變數,如cosnt在*右邊,const修飾指標本身。

      3、函式中使用Const

       (1)const修飾函式引數     

           a. 傳遞過來的引數在函式內不可變(無意義,因為Var本身就是形參)

                      void function(const int Var);

          b. 引數指標所指內容為常量不可變

                      void function(const char* Var);

          c. 引數指標本身不可變(無意義,因為char * Var也是形參)

                       void function(char* const Var);

          d. 引數為引用,為了增加效率同時防止修改,引數不可變--C++特性

                       void function(const Class & Var);

       (2)const修飾函式返回值

           const修飾函式返回值其實用的並不是很多,它的含義和const修飾普通變數以及指標的含義基本相同。

           a.  const int fun1() ;          //這個其實無意義,因為引數返回本身就是賦值

           b.  const int * fun2();        //呼叫時使用const int *pValue = fun2();

                                                       //我們可以把fun2()看成一個變數,即指標內容不可變

           c.  int * const fun3();        //呼叫時使用int* const pValue = fun3();

                                                       //我們可以把fun3()看成一個變數,即指標本身不可變

二、Static

        從字面意思是靜止的、不變的,下面主要從作用域、儲存域方面進行講解。

        1、修飾變數

            修飾變數又分為修飾區域性變數和修飾全域性變數。

            (1)修飾區域性變數

                作用域:只限在本檔案使用(又稱內部變數),外部檔案不能使用,準確的說,作用域是從定義之處開始,到檔案結束,定義之前的程式碼不能使用它。

                儲存域:儲存在靜態區,同時在所處模組初次執行時進行初始化工作,且只初始化一次。

            (2)修飾全域性變數

                作用域:只限在本檔案使用,外部檔案不能使用。

                儲存域:儲存在靜態區,如果不賦初值,編譯期會自動賦初值0或空字元。

           (3)普通變數

                作用域:區域性變數生存週期在模組執行時,執行結束就被立刻釋放,全域性變數在整個檔案和外部檔案(使用extern宣告)都可使用。

                儲存域:區域性變數儲存在棧區,全域性變數儲存在靜態區。

        示例程式一:             

        #include <stdio.h>

        void staticAddVal()
        {
            static int a;
            printf("a=%d ",a);
            a ++;  
        }

        int main()
        {
            staticAddVal();   <span style="color:#009900;">//第一次呼叫輸出a=0;</span>
            staticAddVal();   <span style="color:#009900;">//第二次呼叫記憶了第一次退出的值,輸出a=1</span>
            return 0;
        }

        示例程式二:                            

        //file1.c
        int varA = 1;
        static int varB;
 
        void funA(){} 

         .....

        //file2.c
        extern int varA;     <span style="color:#009900;">//使用file1.cpp中定義的全域性變數</span>
        extern int varB;     <span style="color:#009900;">//錯誤!varB是static型別,無法在其它檔案中使用</span>
   
         .....

        int main()
        {
           ....
        }

        2、修飾函式

              修飾函式使得函式成為靜態函式,但此處的"static"的含義不是指儲存方式,而是指對函式的作用域僅侷限於本檔案(又稱內部函式),利用這一特性可以在不同的檔案中定義同名函式,而不必擔心命名衝突。

        示例程式三:           

        //file1.c
        void funA()
        {
            ....
        }

        static void funB()
        {
            ....
        }

        //file2.c
        extern void funA();   <span style="color:#009900;">//使用file1.c中定義的函式</span>
        extern void funB();   <span style="color:#009900;">//錯誤!無法使用file1.c檔案中的static函式</span>
 
         .....

        int main()
        {
            .....
        }
三、Extern

        修飾符extern用在變數或者函式的宣告前,用來說明此變數/函式是在別處定義過的,要在本檔案中引用。

        注:定義的全域性變數或函式預設的是extern,具有外連性。

       1、extern修飾變數/函式

       示例程式一:        

       //file1.c   
       int iNum = 10;
       int iVar = 9.9;

       void funA(void)
       {
          .....
       }
       static void funB(void)
       {
          .....
       }

       //file2.c
       extern int iNum;         <span style="color:#009900;">//使用file1.c中的變數iNum</span><span style="color:#006600;"> </span>
       extern double iVar;      <span style="color:#009900;">//錯誤!型別不一樣</span>
       extern void funA(void);  <span style="color:#009900;">//呼叫file1.c中的函式funA</span>
       extern void funB(void);  <span style="color:#009900;">//錯誤!static修飾的函式具有隱藏性,不可外用</span>

        .....
       
       int main()
       {
          ...
       }

       2、extern "C"的使用

              在C++環境下使用C函式時,常常會出現編譯器無法找到obj模組中的C函式定義,從而導致連結失敗的情況。

             示例程式二:

       #ifdef __cplusplus
       extern "C" {
       #endif

       /*...*/
 
       #ifdef __cplusplus
       }
       #endif
四、Volatile

        volatile是易變的、不穩定的意思,遇到這個關鍵字宣告的變數,編譯器對訪問該變數的程式碼就不再進行優化,從而可以提供對特殊地址的穩定訪問。

        示例程式一:

               int i  =  10;
               int j  =  i;      //①語句
               int k =  i;      //②語句

        此時編譯器對程式碼進行優化,這是因為①②語句中,i沒有被賦值,這是編譯器認為i的值沒有發生改變,所以在①語句時從記憶體中取出i的值賦給j之後,這個值並沒有被丟掉,而是在②語句時繼續賦值給k。

        示例程式二:

               volatile int i  =  10;
               int j  =  i;      //①語句
               int k =  i;      //②語句

       volatile關鍵字告訴編譯器,i隨時可能發生變化的,每次使用他的時候必須從記憶體中取出i的值,因而編譯器生存的彙編程式碼會重新從i的地址處讀取資料放在k中。