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

C語言核心關鍵字與程式設計精要大全

     編輯:關於C

一、關鍵字深度解析

1. static:雙重身份的關鍵字

修飾變數:延長生命週期、限制作用域

  • 靜態區域變數: 儲存在靜態區,函數結束後值保留,下次呼叫可繼續使用。預設初始化為 0。
  • 靜態全域變數: 僅在定義該變數的源檔案內可見(內部連結),避免多檔案專案命名衝突。
void counter(void) {
    static int count = 0;  // 僅初始化一次
    printf("%d ", ++count);
}
int main() {
    for (int i = 0; i < 5; i++) counter();  // 輸出 1 2 3 4 5
}

修飾函數:內部函數

static void helper(void) 限制該函數僅在本編譯單元可見,實現封裝,減少連結器符號汙染。

2. sizeof:編譯期運算子,非函數

  • 對型別使用需加括號:sizeof(int);對變數可省略:sizeof arr。
  • 陣列參數退化為指標時 sizeof 回傳指標大小,非陣列總大小。

3. signed / unsigned:有號與無號

整型預設為 signed;char 是否有號由實作定義,跨平台時建議顯式指定。

4. float 比較陷阱

絕對避免 float == 0.0。正確做法:fabs(x - target) < EPSILON。

5. if-else 風格建議

優先處理正常流程,異常情況置於 else,減少巢狀層級,提升可讀性。

6. 迴圈優化:長迴圈內層、短迴圈外層

將迴圈次數最多的放在最內層,減少 CPU 切換迴圈層級的開銷,提升快取命中率。

7. void:無型別的型別

  • void func(void):明確表示無參數(C89 中 func() 代表參數未指定)。
  • void *:通用指標,可指向任意型別資料,需強制轉型後解參考。
  • 不可宣告 void a; 或 void func(void a)。

8. const:唯讀承諾與最佳化提示

修飾指標的四種組合

宣告指標可變?指向物件可變?口訣
const int *p是否從右讀:p 是指向 const int 的指標
int const *p是否同上,const 修飾左側型別
int *const p否是p 是 const 指標,指向 int
const int *const p否否雙重 const

修飾函數參數

void print_str(const char *str);  // 承諾不修改 str 指向的內容

9. extern:跨檔案宣告

僅宣告不定義,告訴編譯器「符號在別處定義」。標頭檔中對全域變數/函數使用 extern,源檔中定義一次。

10. struct:結構體

  • 空結構體大小為 1 byte(C++),C 標準視為不完整型別。
  • 成員預設 public(C++ 中 class 預設 private)。
  • 記憶體對齊遵循「成員對齊、整體對齊」原則,可用 #pragma pack 或屬性調整。

11. union:共用體

  • 所有成員共用同一塊記憶體,大小等於最大成員大小(對齊後)。
  • 同一時間只能存取一個成員,常用於型別轉換、通訊協定封包、節省記憶體。
union Data {
    int i;
    float f;
    char bytes[4];
};

12. typedef:型別別名

參見文章 1555 詳細說明。

二、前處理器指令

1. #if / #elif / #else / #endif:條件編譯

常用於平台差異、功能開關、版本控制。

#if defined(__linux__)
    #include 
#elif defined(_WIN32)
    #include 
#else
    #error "Unsupported platform"
#endif

2. #define:巨集定義與替換規則

參數加括號鐵律

// ❌ 危險
#define SQR(x) x * x
// SQR(10+1) -> 10+1*10+1 = 21

// ✅ 安全
#define SQR(x) ((x) * (x))
// SQR(10+1) -> ((10+1) * (10+1)) = 121

多行巨集使用 do { ... } while(0) 包裹,確保語句行為一致。

三、指標與陣列:核心區別與進階技巧

1. 陣列名不是指標

  • int a[5]:a 是「陣列首元素地址」(右值),&a 是「整個陣列地址」(型別 int (*)[5])。
  • a + 1 增加 sizeof(int);&a + 1 增加 sizeof(int[5])。
  • 陣列名不可作左值(a = p 錯誤)。

2. 跨檔案陣列與指標聲明不匹配會導致災難

// file1.c
char a[100];

// file2.c ❌ 錯誤
extern char *a;  // 編譯器以為 a 是指標(4/8 bytes),實際是陣列(100 bytes)
// 存取 a[i] 會先讀取 a 的前 4/8 bytes 當作位址 -> 崩潰

// file2.c ✅ 正確
extern char a[];       // 或 extern char a[100];

根本原因: 陣列即地址,指標儲存地址。編譯器依聲明型別產生機器碼,聲明錯誤導致指令序列錯誤。

3. 函數參數:陣列退化為指標

void func(int arr[]);        // 等同於
void func(int *arr);         // 等同於
void func(int arr[10]);      // 10 被忽略,僅作文件用途

若需保留大小資訊,需額外傳遞長度參數,或使用指向陣列的指標:void func(int (*arr)[10])。

4. 指標運算以元素大小為單位

int *p; p++; 位址增加 sizeof(int),而非 1 byte。

總結

C 語言看似簡單,實則暗藏精微。深入理解 static、const、extern 的儲存類別與連結屬性,掌握指標與陣列的本質區別,善用前處理器進行條件編譯與安全巨集定義,是從「能寫出跑得動的程式」進階到「寫出可維護、可移植、高效能系統程式」的必經之路。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved