static、extern 是 C 語言存儲類別與鏈接屬性的核心關鍵字,指針函數(返回指針的函數)與函數指針(指向函數的指針)易混淆卻用途截然不同。本文系統梳理三者的語義模型、作用域規則、內存佈局、跨文件協作模式及實戰陷阱。
void counter() {
static int count = 0; // 僅初始化一次,保持值
printf("%d\n", count++);
}
_Thread_local (C11)// file1.c static int internal_var = 42; // 僅 file1 可見 int global_var = 100; // 外部鏈接,全程序可見
static void helper() { ... } // 僅本文件可調用
void api() { helper(); } // 對外接口
void foo(int n, int arr[static n]); // 提示編譯器 arr 至少 n 元素
// common.h extern int shared_counter; // 僅聲明 extern void init_counter();
// common.c
#include "common.h"
int shared_counter = 0; // 定義(分配內存)
void init_counter() { shared_counter = 100; }
// main.c
#include "common.h"
int main() {
init_counter();
printf("%d\n", shared_counter); // 100
}
// 以下等價 extern int func(int); int func(int); // 函數聲明默認 extern
extern int a, b; // 提前聲明
void func() { printf("%d %d", a, b); }
int a = 1, b = 2; // 定義在後,合法
| 維度 | static 全局/函數 | extern 全局/函數 | 普通全局(無修飾) |
|---|---|---|---|
| 鏈接類型 | 內部鏈接 | 外部鏈接 | 外部鏈接 |
| 可見範圍 | 僅定義文件 | 整個程序(需聲明) | 整個程序 |
| 符號導出 | 否 | 是 | 是 |
| 多文件定義 | 允許同名(各自獨立) | 僅一處定義,多處聲明 | 僅一處定義 |
| 典型用途 | 文件級私有、封裝 | 跨文件共享、庫接口 | 舊代碼、小程序 |
// 語法:返回類型 *函數名(參數) char *substring(char *s, int start, int len); // 返回字符串指針 int *alloc_array(int n); // 返回動態數組指針
關鍵點:返回指針指向的內存必須有效(靜態、堆、調用者提供),**嚴禁返回局部數組指針**。
// 語法:返回類型 (*指針名)(參數類型列表) int (*cmp)(const void *, const void *); // qsort 比較函數指針 void (*handler)(int signum); // 信號處理器類型
用途:回調、狀態機、插件架構、多態模擬、qsort/bsearch 標準庫算法。
char *bad_substring(char *s, int i, int j) {
char buf[100]; // 局部數組,棧上,函數返回即失效
// ...
return buf; // 錯誤!返回棧地址
}
char *good_substring(char *s, int i, int j) {
static char buf[100]; // 靜態存儲,生命周期全程
// ...
return buf; // 正確,但線程不安全、不可重入
}
// 更好:調用者提供緩衝區
void safe_substring(char *s, int i, int j, char *out, size_t sz);
typedef void (*CmdFunc)(const char *arg);
void cmd_help(const char *arg) { ... }
void cmd_quit(const char *arg) { ... }
CmdFunc cmd_table[] = {
["help"] = cmd_help,
["quit"] = cmd_quit,
};
// 調用:cmd_table["help"]("--verbose");
#ifndef COUNTER_H
#define COUNTER_H
#ifdef __cplusplus extern "C" { #endif
// 不透明指針隱藏實現細節
typedef struct Counter Counter;
Counter *counter_create(int initial);
void counter_increment(Counter *c);
int counter_get(const Counter *c);
void counter_destroy(Counter *c);
#ifdef __cplusplus } #endif
#endif
#include "counter.h" #includestruct Counter { int value; }; // 定義在 .c 中,外部不可見 Counter *counter_create(int initial) { Counter *c = malloc(sizeof(*c)); if (c) c->value = initial; return c; } void counter_increment(Counter *c) { if (c) c->value++; } int counter_get(const Counter *c) { return c ? c->value : 0; } void counter_destroy(Counter *c) { free(c); }
#include "counter.h" #includeint main() { Counter *c = counter_create(10); counter_increment(c); printf("Value: %d\n", counter_get(c)); // 11 counter_destroy(c); return 0; }
extern 聲明與不透明類型,.c 文件定義 static 私有實體與具體結構