C 語言的變數與函數不僅有資料型別,更具備儲存期限(生命週期)、作用域(可見範圍)、連結屬性(跨檔案可見性)三大屬性。搞懂這三者交織關係,是寫出模組化、可維護 C 程式的關鍵。
| 類別 | 定義位置 | 作用域 | 生命週期 | 預設初值 | 跨檔案可見 |
|---|---|---|---|---|---|
| 區域變數 | 區塊內部 | 定義處至區塊結束 | 區塊執行期間 | 無(亂碼) | 否 |
| 全域變數(外部) | 函式外部 | 定義處至檔案結尾 | 程式啟動至結束 | 0 | 是(預設) |
| 全域變數(內部) | 函式外部 + static | 定義處至檔案結尾 | 程式啟動至結束 | 0 | 否 |
| 靜態區域變數 | 區塊內部 + static | 定義處至區塊結束 | 程式啟動至結束 | 0 | 否 |
extern 宣告呼叫,全專案不可有同名外部函數。static):僅限本檔案可見,不同檔案可有同名內部函數,避免命名衝突。static 與 extern 關鍵字對照表| 關鍵字 | 修飾對象 | 效果 |
|---|---|---|
static | 全域變數/函數 | 限定為內部連結,隱藏符號,僅本編譯單元可見 |
| 區域變數 | 延長生命週期至程式結束,儲存於靜態區,不改變作用域 | |
extern | 全域變數宣告 | 告知編譯器「定義在別處」,不配置記憶體,僅作前向宣告 |
| 函數宣告 | 標示為外部連結(預設即為外部,通常可省略) |
counter.h
#ifndef COUNTER_H
#define COUNTER_H
// 外部變數宣告(定義在 counter.c)
extern int g_total_calls;
// 外部函數宣告
void increment_counter(void);
int get_counter(void);
#endif
counter.c
#include "counter.h"
// 定義外部變數(配置記憶體)
int g_total_calls = 0;
// 內部函數:本檔案私有,外部不可見
static void log_call(const char *func) {
printf("[LOG] %s called, total=%d\n", func, g_total_calls);
}
void increment_counter(void) {
g_total_calls++;
log_call(__func__);
}
int get_counter(void) {
return g_total_calls;
}
main.c
#include
#include "counter.h"
int main(void) {
increment_counter();
increment_counter();
printf("Total: %d\n", get_counter()); // 輸出 2
return 0;
}
extern int x; 放在 .h,int x = 0; 放在唯一的 .c,防止重複定義錯誤。_Thread_local (C11)。static 隱藏實作細節,降低耦合,加快連結速度。掌握儲存類別與連結屬性,能讓你在大型專案中精準控制符號可見性、避免命名汙染、撰寫更安全的程式庫介面。