1. 程式人生 > >C 存儲類

C 存儲類

使用範圍 efi log 指令 span int 調用 有一個 blog

C 存儲類

存儲類定義 C 程序中變量/函數的範圍(可見性)和生命周期。這些說明符放置在它們所修飾的類型之前。下面列出 C 程序中可用的存儲類:

  • auto
  • register
  • static
  • extern

auto 存儲類

auto 存儲類是所有局部變量默認的存儲類。

{
   int mount;
   auto int month;
}

上面的實例定義了兩個帶有相同存儲類的變量,auto 只能用在函數內,即 auto 只能修飾局部變量。

register 存儲類

register 存儲類用於定義存儲在寄存器中而不是 RAM 中的局部變量。這意味著變量的最大尺寸等於寄存器的大小(通常是一個詞),且不能對它應用一元的 ‘&‘ 運算符(因為它沒有內存位置)。

{
   register int  miles;
}

寄存器只用於需要快速訪問的變量,比如計數器。還應註意的是,定義 ‘register‘ 並不意味著變量將被存儲在寄存器中,它意味著變量可能存儲在寄存器中,這取決於硬件和實現的限制。

static 存儲類

static 存儲類指示編譯器在程序的生命周期內保持局部變量的存在,而不需要在每次它進入和離開作用域時進行創建和銷毀。因此,使用 static 修飾局部變量可以在函數調用之間保持局部變量的值。

static 修飾符也可以應用於全局變量。當 static 修飾全局變量時,會使變量的作用域限制在聲明它的文件內。

static 是全局變量的默認存儲類,以下兩個變量 (count 和 road) 都有一個 static 存儲類。

static int Count;
int Road;

main()
{
    printf("%d\n", Count);
    printf("%d\n", Road);
 }

以下實例演示了 static 修飾全局變量和局部變量的應用:

實例

#include <stdio.h>
 
/* 函數聲明 */
void func1(void);
 
static int count=10;        /* 全局變量 - static 是默認的 */
 
int main()
{
  while (count--) {
      func1();
  }
  
return 0; } void func1(void) { /* ‘thingy‘ 是 ‘func1‘ 的局部變量 - 只初始化一次 * 每次調用函數 ‘func1‘ ‘thingy‘ 值不會被重置。 */ static int thingy=5; thingy++; printf(" thingy 為 %d , count 為 %d\n", thingy, count); }

實例中 count 作為全局變量可以在函數內使用,thingy 使用 static 修飾後,不會再每次調用時重置。

可能您現在還無法理解這個實例,因為我已經使用了函數和全局變量,這兩個概念目前為止還沒進行講解。即使您現在不能完全理解,也沒有關系,後續的章節我們會詳細講解。當上面的代碼被編譯和執行時,它會產生下列結果:

 thingy 為 6 , count 為 9
 thingy 為 7 , count 為 8
 thingy 為 8 , count 為 7
 thingy 為 9 , count 為 6
 thingy 為 10 , count 為 5
 thingy 為 11 , count 為 4
 thingy 為 12 , count 為 3
 thingy 為 13 , count 為 2
 thingy 為 14 , count 為 1
 thingy 為 15 , count 為 0

extern 存儲類

extern 存儲類用於提供一個全局變量的引用,全局變量對所有的程序文件都是可見的。當您使用 ‘extern‘ 時,對於無法初始化的變量,會把變量名指向一個之前定義過的存儲位置。

當您有多個文件且定義了一個可以在其他文件中使用的全局變量或函數時,可以在其他文件中使用 extern 來得到已定義的變量或函數的引用。可以這麽理解,extern 是用來在另一個文件中聲明一個全局變量或函數。

extern 修飾符通常用於當有兩個或多個文件共享相同的全局變量或函數的時候,如下所示:

第一個文件:main.c

實例

#include <stdio.h>
 
int count ;
extern void write_extern();
 
main()
{
   count = 5;
   write_extern();
}

第二個文件:support.c

實例

#include <stdio.h>
 
extern int count;
 
void write_extern(void)
{
   printf("count is %d\n", count);
}

在這裏,第二個文件中的 extern 關鍵字用於聲明已經在第一個文件 main.c 中定義的 count。現在 ,編譯這兩個文件,如下所示:

 $ gcc main.c support.c

這會產生 a.out 可執行程序,當程序被執行時,它會產生下列結果:

count is 5

筆記列表

  1. auto 是局部變量的默認存儲類, 限定變量只能在函數內部使用;

    register 代表了寄存器變量,不在內存中使用;

    static是全局變量的默認存儲類,表示變量在程序生命周期內可見;

    extern 表示全局變量,即對程序內所有文件可見,類似於Java中的public關鍵字;

  2. C 語言中全局變量、局部變量、靜態全局變量、靜態局部變量的區別

    從作用域看:

    1、全局變量具有全局作用域。全局變量只需在一個源文件中定義,就可以作用於所有的源文件。當然,其他不包含全局變量定義的源文件需要用extern 關鍵字再次聲明這個全局變量。

    2、靜態局部變量具有局部作用域,它只被初始化一次,自從第一次被初始化直到程序運行結束都一直存在,它和全局變量的區別在於全局變量對所有的函數都是可見的,而靜態局部變量只對定義自己的函數體始終可見。

    3、局部變量也只有局部作用域,它是自動對象(auto),它在程序運行期間不是一直存在,而是只在函數執行期間存在,函數的一次調用執行結束後,變量被撤銷,其所占用的內存也被收回。

    4、靜態全局變量也具有全局作用域,它與全局變量的區別在於如果程序包含多個文件的話,它作用於定義它的文件裏,不能作用到其它文件裏,即被static關鍵字修飾過的變量具有文件作用域。這樣即使兩個不同的源文件都定義了相同名字的靜態全局變量,它們也是不同的變量。

    從分配內存空間看:

    1、全局變量,靜態局部變量,靜態全局變量都在靜態存儲區分配空間,而局部變量在棧裏分配空間

    2、全局變量本身就是靜態存儲方式, 靜態全局變量當然也是靜態存儲方式。這兩者在存儲方式上並無不同。這兩者的區別雖在於非靜態全局變量的作用域是整個源程序,當一個源程序由多個源文件組成時,非靜態的全局變量在各個源文件中都是有效的。而靜態全局變量則限制了其作用域,即只在定義該變量的源文件內有效,在同一源程序的其它源文件中不能使用它。由於靜態全局變量的作用域局限於一個源文件內,只能為該源文件內的函數公用,因此可以避免在其它源文件中引起錯誤。

    • 1)靜態變量會被放在程序的靜態數據存儲區(全局可見)中,這樣可以在下一次調用的時候還可以保持原來的賦值。這一點是它與堆棧變量和堆變量的區別。
    • 2)變量用static告知編譯器,自己僅僅在變量的作用範圍內可見。這一點是它與全局變量的區別。

    從以上分析可以看出, 把局部變量改變為靜態變量後是改變了它的存儲方式即改變了它的生存期。把全局變量改變為靜態變量後是改變了它的作用域,限制了它的使用範圍。因此static 這個說明符在不同的地方所起的作用是不同的。應予以註意。

    Tips:

    • A.若全局變量僅在單個C文件中訪問,則可以將這個變量修改為靜態全局變量,以降低模塊間的耦合度;
    • B.若全局變量僅由單個函數訪問,則可以將這個變量改為該函數的靜態局部變量,以降低模塊間的耦合度;
    • C.設計和使用訪問動態全局變量、靜態全局變量、靜態局部變量的函數時,需要考慮重入問題,因為他們都放在靜態數據存儲區,全局可見;
    • D.如果我們需要一個可重入的函數,那麽,我們一定要避免函數中使用static變量(這樣的函數被稱為:帶"內部存儲器"功能的的函數)
    • E.函數中必須要使用static變量情況:比如當某函數的返回值為指針類型時,則必須是static的局部變量的地址作為返回值,若為auto類型,則返回為錯指針。
  3. auto 普通局部棧變量,是自動存儲,這種對象會自動創建和銷毀 ,建議這個變量要放在堆棧上面,調用函數時分配內存,函數結束時釋放內存。一般隱藏auto默認為自動存儲類別。我們程序都變量大多是自動變量。

    實例 auto.c

    #include <stdio.h>
    
    int main(void)
    {
        auto int i = 9; /* 聲明局部變量的關鍵字是 auto; 因可以省略, 幾乎沒人使用 */   
        printf("%d\n", i);  
        getchar();
        return 0;
    }

    Register變量:動態和靜態變量都是存放在內存中,程序中遇到該值時用控制器發指令將變量的值送到運算器中,需要存數再保存到內存中。如果頻繁使用一個變量,比如一個函數體內的多次循環每次都引用該局部變量,我們則可以把局部變量的值放到CPU的寄存器中,叫寄存器變量。不需要多次到內存中存取提高效率。但是只能局部自動變量和形參可以做寄存器變量。在函數調用時占用一些寄存器,函數結束時釋放。不同系統對register要求也不一樣,比如對定義register變量個數,數據類型等限制,有的默認為自動變量處理。所以在程序一般也不用。

    實例 register.c

    #include <stdio.h>
    #include <time.h>
    
    #define TIME 1000000000
    int m, n = TIME; /* 全局變量 */
    
    int main(void)
    {   
        time_t start, stop;
        register int a, b = TIME; /* 寄存器變量 */
        int x, y = TIME;          /* 一般變量   */
    
        time(&start);
        for (a = 0; a < b; a++);
        time(&stop);
        printf("寄存器變量用時: %ld 秒\n", stop - start);
        
        time(&start);
        for (x = 0; x < y; x++);
        time(&stop);
        printf("一般變量用時: %ld 秒\n", stop - start);
        
        time(&start);
        for (m = 0; m < n; m++);
        time(&stop);
        printf("全局變量用時: %ld 秒\n", stop - start);
    
        return 0;
    }

    輸出結果:

    寄存器變量用時: 1 秒
    一般變量用時: 8 秒
    全局變量用時: 9

C 存儲類