首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C 語言變數儲存類別完整解析:auto、static、extern、register、volatile、restrict

     編輯:關於C語言

儲存類別與作用域/生命週期/連結屬性

關鍵字儲存區域作用域生命週期預設初值連結屬性
auto (局部預設)棧塊內函數調用期間垃圾值無連結
static (局部)靜態區 (.data/.bss)塊內程式全程0 / NULL無連結
static (全域)靜態區檔案內程式全程0 / NULL內部連結
extern靜態區全域 (聲明處可見)程式全程0 / NULL外部連結
register寄存器/棧塊內函數調用期間垃圾值無連結
(無關鍵字全域)靜態區全域程式全程0 / NULL外部連結

1. 自動變數 `auto` (隱式)


void func() {
    auto int a = 10; // 等同 int a = 10;
    // a 佔用棧空間,函數返回即銷毀
}

幾乎不寫 `auto`,C++11 賦予新意(類型推導)。

2. 靜態局部變數 `static`

特性:保持值跨函數調用;僅初始化一次;預設歸零;線程不安全(共享單一實例)。


void counter() {
    static int count = 0; // 僅第一次執行初始化
    printf("Call %d\n", ++count);
}
int main() { counter(); counter(); counter(); } // 輸出 1, 2, 3

3. 靜態全域變數 / 函數 `static`

作用:限制連結可見性為**當前編譯單元 (檔案)**。實現封裝,避免符號衝突。


// file1.c
static int internal_id = 100;      // 僅 file1 可見
static void helper() { ... }       // 僅 file1 可呼叫

// file2.c
// extern int internal_id; // 鏈接錯誤:未定義
// helper();               // 鏈接錯誤

4. 外部聲明 `extern`

用途:跨檔案共享全域變數/函數。聲明 ≠ 定義。


// global.h
extern int g_count;      // 聲明 (無分配空間)
extern void init_sys();  // 函數聲明 (extern 可省略)

// global.c
#include "global.h"
int g_count = 0;         // 定義 (分配空間,僅一次)
void init_sys() { g_count = 10; }

// main.c
#include "global.h"
int main() { init_sys(); printf("%d", g_count); }

陷阱:頭檔中 `int g = 0;` 會導致多檔包含產生多重定義錯誤。頭檔只能 `extern`。

5. 寄存器變數 `register`

建議編譯器:將變數放入 CPU 寄存器加速存取。**不可取址 (`&var` 錯誤)**。現代編譯器 (`-O2`) 自動分配寄存器,`register` 關鍵字多為提示/忽略。


void fast_loop() {
    register int i; // 建議放入寄存器
    for (i = 0; i < 1000000; i++); 
    // &i; // 編譯錯誤:address of register variable requested
}

6. `volatile`:防優化/硬體訪問

語義:告訴編譯器「此變數值可能在程式不知情下改變(硬體暫存器、中斷服務程式、多執行緒共享變數)」,**每次讀寫必須訪問記憶體**,禁用快取/寄存器優化。


// 硬體暫存器映射
volatile uint32_t *UART_DR = (uint32_t*)0x40004000;
*UART_DR = 'A'; // 寫入發送資料暫存器

// 中斷標誌
volatile int flag = 0;
void ISR() { flag = 1; }
void main_loop() { while (!flag); /* 編譯器不會優化成 while(1) */ }

// const volatile: 僅硬體可寫 (只讀暫存器)
const volatile uint32_t *STATUS_REG = (uint32_t*)0x40004004;

7. `restrict` (C99):指標別名優化提示

語義:指標 `p` 為**唯一**訪問該記憶體區塊的途徑(無別名)。編譯器可激進優化(向量化、重排、快取)。


// 標準庫 memcpy 原型
void *memcpy(void *restrict dest, const void *restrict src, size_t n);
// 告訴編譯器 dest 和 src 記憶體不重疊,可用 SIMD 指令優化

// 錯誤用法:違反 restrict 承諾 -> 未定義行為
void bad(int *restrict a, int *restrict b) { *a = 1; *b = 2; }
int x; bad(&x, &x); // a 和 b 指向同一地址,違反 restrict

總結選擇指南

  • 局部臨時變數:**無關鍵字** (隱式 `auto`)。
  • 需跨調用保持狀態:**`static` 局部**。
  • 模組內部全域狀態:**`static` 全域**。
  • 跨檔案共享狀態:**`extern` 聲明 + 單一檔案定義**。
  • 硬體暫存器/中斷標誌/多執行緒旗標:**`volatile`**。
  • 高效能指標函數參數 (無別名保證):**`restrict`**。
  • 極熱點迴圈計數器:現代編譯器自動優化,**無需 `register`**。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved