static關鍵字的作用

北极甜虾哟發表於2024-06-17

分析C語言static關鍵字的作用

目錄
  • 分析C語言static關鍵字的作用
    • 1.靜態儲存期(區域性變數使用static時)
    • 2.靜態全域性變數
    • 3.static與函式一起使用

  • 先來看一個案例
#include <stdio.h>

int a=5;
void show_val(void)
{
    int b=3;
    static int c=2;
    a+=5;
    b+=5;
    c+=5;
    printf("a = %d,b = %d,c = %d\n",a,b,c);
    c = b;
}
int main(void)
{
    int b=0;
    static int c;
    a += 3;
    show_val();
    b += 3;
    show_val ();
    return 0;
}

img

第一次列印結果:a = 13,b = 8,c = 7

第二次列印結果:a = 18,b = 8,c = 13

  • 為什麼會有這樣的結果呢?主要受static關鍵字的影響,下面就來分析static關鍵字的作用。

1.靜態儲存期(區域性變數使用static時)

1.當static關鍵字用於函式內的區域性變數時,它改變了該變數的儲存期。通常,函式內的區域性變數具有自動儲存期,這意味著它們在進入函式時建立,在離開函式時銷燬。

2.但是,當區域性變數被宣告為static時,它獲得了靜態儲存期,這意味著該變數在程式開始時分配記憶體,在程式結束時釋放記憶體。
3.靜態區域性變數的初始值只會在第一次進入函式時設定,之後呼叫函式時不會再次設定。因此,靜態區域性變數可以用來跟蹤函式被呼叫的次數,或者記住跨函式呼叫之間的某些狀態。

//例如:
void Function() {  
    static int count = 0;  
    count++;  
    printf("Function has been called %d times\n", count);  
}  
// 多次呼叫 counterFunction 會顯示遞增的計數
int main()
{
    for(int i = 0;i < 5,++i)
    {
        function();
    }
    return 0;
}

img

2.靜態全域性變數

1.全域性變數可以使用 static 關鍵字進行修飾。但是,當我們在全域性作用域(即檔案級作用域)中使用 static 修飾一個變數時,它的意義與在函式內部(區域性變數)使用 static 修飾變數時有所不同。

2.我們知道,當在函式內部使用 static 修飾一個變數時,該變數在函式呼叫之間保持其值。這意味著它只會在第一次呼叫該函式時被初始化,並在隨後的函式呼叫中保持其值。

3.當在全域性作用域中使用 static 修飾一個變數時,該變數具有內部連結。這意味著該變數只在其定義的檔案中可見,對其他檔案是不可見的。這通常用於限制全域性變數的可見性,防止其他檔案意外地訪問或修改它。

因此,靜態全域性變數的特性是:

(1)它的作用域是全域性的,意味著在程式中的任何函式內部都可以訪問它(只要它們有正確的訪問許可權)。
(2)它的生命週期是整個程式的執行期間,從程式開始到程式結束。
(3)由於它是 static 的,所以它的可見性被限制在定義它的檔案內部。這意味著如果你試圖在另一個原始檔中訪問這個靜態全域性變數,你將無法做到(除非使用某種特殊的連結技術,如外部宣告)。

//例如:
// file1.c  
static int Val = 10;  
  
void func()
{  
    printf("%d\n", Val);  
}  
  
// file2.c  
//...
    
// 這裡不能訪問 Val,因為它在 file1.c 中是 static 的
//在這個例子中,Val 只在 file1.c 中可見,因此 file2.c 不能訪問它。

1.注意:在一個C語言工程專案中,我們往往有很多的.c原始檔。如果兩個或多個.c原始檔定義了相同名字的全域性變數(即具有外部連結的變數),那麼這會導致連結器錯誤,因為連結器會在試圖將多個目標檔案合併成一個可執行檔案或庫時,發現存在名稱衝突的全域性符號。

2.因為每個.c原始檔在編譯後都會生成一個目標檔案(比如.o檔案),這些目標檔案包含了原始檔中的函式和全域性變數的資訊。當連結器試圖將這些目標檔案合併成一個可執行檔案時,它會查詢所有全域性符號的定義,並確保每個符號只被定義一次。因此如果兩個或多個目標檔案定義了相同的全域性變數,連結器會報告一個錯誤,指出存在重複定義的符號。因此避免在多個.c原始檔中使用相同的變數名尤為重要,(即使全域性變數的型別不同,但只要它們的名字相同,並且都是具有外部連結的全域性變數,那麼在不同的.c原始檔中定義它們仍然會導致連結器錯誤)。

如下是避免這種情況的方法:

(1)使用不同的變數名:這是最簡單的方法,只需確保每個.c檔案中的全域性變數都有唯一的名稱。

(2)使用static關鍵字:在全域性變數的宣告前新增static關鍵字可以將其作用域限制在單個原始檔內。這樣,即使兩個或多個原始檔都包含了相同名稱的static全域性變數,連結器也不會報告錯誤,因為這些變數實際上是在不同的作用域中定義的。

(3)使用外部變數宣告:在一個.c檔案中定義全域性變數,並在其他需要使用這個變數的.c檔案中使用extern關鍵字宣告它。這樣,所有的.c檔案都共享同一個全域性變數的定義。(extern關鍵字可以宣告一個函式或者一個變數的屬性是外部可連結的,意味著可以被外部檔案呼叫。)

//例如:
// file1.c  
int val = 10; // 定義全域性變數  
 
// file2.c  
extern int val; // 宣告全域性變數,但不定義它  
 
// 然後在file2.c中可以使用val

3.static與函式一起使用

static與函式一起使用時,它主要有兩個主要用途:檔案作用域或內部連結。

當你在一個C原始檔的檔案作用域(即在所有函式之外)中宣告一個函式為static時,這個函式的連結屬性會被改變為內部連結。這意味著該函式只能在宣告它的原始檔中被訪問,而不能從其他原始檔中被連結或訪問。
這有助於隱藏實現細節,使得庫的實現者可以提供某些功能,而不需要暴露這些功能的介面給庫的終端使用者。

//例如:
static void function()
{  
// ......  
}  
// 其他原始檔不能呼叫function

相關文章