C語言中auto,register,static,const,volatile的區別

來源:互聯網
上載者:User

1)auto
  這個關鍵字用於聲明變數的生存期為自動,即將不在任何類、結構、枚舉、聯合和函數中定義的變數視為全域變數,而在函數中定義的變數視為局部變數。這個關鍵字不怎麼多寫,因為所有的變數預設就是auto的。

(2)register
  這個關鍵字命令編譯器儘可能的將變數存在CPU內部寄存器中而不是通過記憶體定址訪問以提高效率。

(3)static
  常見的兩種用途:
    1>統計函數被調用的次數;
    2>減少局部數組建立和賦值的開銷.變數的建立和賦值是需要一定的處理器開銷的,特別是數組等含有較多元素的儲存類型。在一些含有較多的變數並且被經常調用的函數中,可以將一些數組聲明為static類型,以減少建立或者初始化這些變數的開銷.
  詳細說明:
    1>、變數會被放在程式的全域儲存區中,這樣可以在下一次調用的時候還可以保持原來的賦值。這一點是它與棧變數和堆變數的區別。
    2>、變數用static告知編譯器,自己僅僅在變數的作用範圍內可見。這一點是它與全域變數的區別。
    3>當static用來修飾全域變數時,它就改變了全域變數的範圍,使其不能被別的程式extern,限制在了當前檔案裡,但是沒有改變其存放位置,還是在全域靜態儲存區。

  使用注意:
    1>若全域變數僅在單個C檔案中訪問,則可以將這個變數修改為靜態全域變數,以降低模組間的耦合度;
    2>若全域變數僅由單個函數訪問,則可以將這個變數改為該函數的靜態局部變數,以降低模組間的耦合度;
    3>設計和使用訪問動態全域變數、靜態全域變數、靜態局部變數的函數時,需要考慮重入問題(只要輸入資料相同就應產生相同的輸出)。

(4)const
  被const修飾的東西都受到強制保護,可以預防意外的變動,能提高程式的健壯性。它可以修飾函數的參數、傳回值,甚至函數的定義體。
  作用:
    1>修飾輸入參數
      a.對於非內部資料類型的輸入參數,應該將“值傳遞”的方式改為“const引用傳遞”,目的是提高效率。例如將void Func(A a) 改為void Func(const A &a)。
      b.對於內部資料類型的輸入參數,不要將“值傳遞”的方式改為“const引用傳遞”。否則既達不到提高效率的目的,又降低了函數的可理解性。例如void Func(int x) 不應該改為void Func(const int &x)。
    2>用const修飾函數的傳回值
      a.如果給以“指標傳遞”方式的函數傳回值加const修飾,那麼函數傳回值(即指標)的內容不能被修改,該傳回值只能被賦給加const修飾的同類型指標。
       如對於: const char * GetString(void);
       如下語句將出現編譯錯誤:
        char *str = GetString();//cannot convert from 'const char *' to 'char *';
       正確的用法是:
       const char *str = GetString();
      b.如果函數傳回值採用“值傳遞方式”,由於函數會把傳回值複製到外部臨時的儲存單元中,加const修飾沒有任何價值。如不要把函數int GetInt(void) 寫成const int GetInt(void)。
    3>const成員函數的聲明中,const關鍵字只能放在函式宣告的尾部,表示該類成員不修改對象.

   說明:
    const type m; //修飾m為不可改變
   樣本:
    typedef char * pStr; //新的類型pStr;
    char string[4] = "abc";
    const char *p1 = string;
    p1++; //正確,上邊修飾的是*p1,p1可變
    const pStr p2 = string;
    p2++; //錯誤,上邊修飾的是p2,p2不可變,*p2可變
   同理,const修飾指標時用此原則判斷就不會混淆了。
    const int *value; //*value不可變,value可變
    int* const value; //value不可變,*value可變
    const (int *) value; //(int *)是一種type,value不可變,*value可變
              //邏輯上這樣理解,編譯不能通過,需要tydef int* NewType;
    const int* const value;//*value,value都不可變

(5)volatile
  表明某個變數的值可能在外部被改變,最佳化器在用到這個變數時必須每次都小心地重新讀取這個變數的值,而不是使用儲存在寄存器裡的備份。它可以適用於基礎類型如:int,char,long......也適用於C的結構和C++的類。當對結構或者類對象使用volatile修飾的時候,結構或者類的所有成員都會被視為volatile.
  該關鍵字在多線程環境下經常使用,因為在編寫多線程的程式時,同一個變數可能被多個線程修改,而程式通過該變數同步各個線程。
  簡單樣本:
   DWORD __stdcall threadFunc(LPVOID signal)
   {
     int* intSignal="reinterdivt"_cast(signal);
     *intSignal=2;
     while(*intSignal!=1)
     sleep(1000);
     return 0;
   }
  該線程啟動時將intSignal 置為2,然後迴圈等待直到intSignal 為1 時退出。顯然intSignal的值必須在外部被改變,否則該線程不會退出。但是實際啟動並執行時候該線程卻不會退出,即使在外部將它的值改為1,看一下對應的偽彙編代碼就明白了:
     mov ax,signal
     label:
     if(ax!=1)
     goto label
  對於C編譯器來說,它並不知道這個值會被其他線程修改。自然就把它cache在寄存器裡面。C 編譯器是沒有線程概念的,這時候就需要用到volatile。volatile 的本意是指:這個值可能會在當前線程外部被改變。也就是說,我們要在threadFunc中的intSignal前面加上volatile關鍵字,這時候,編譯器知道該變數的值會在外部改變,因此每次訪問該變數時會重新讀取,所作的迴圈變為如下面偽碼所示:
     label:
     mov ax,signal
     if(ax!=1)
     goto label
  注意:一個參數既可以是const同時是volatile,是volatile因為它可能被意想不到地改變。它是const因為程式不應該試圖去修改它。

(6)extern
  extern 意為“外來的”···它的作用在於告訴編譯器:有這個變數,它可能不存在當前的檔案中,但它肯定要存在於工程中的某一個源檔案中或者一個Dll的輸出中。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.