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

C 語言中級知識體系總覽:sizeof、對齊、指標、結構體、前置處理與函數進階

     編輯:關於C語言

一、sizeof 關鍵細節

  • **編譯期常數** (VLA 除外),不產生執行期指令。
  • `sizeof(型別)` 需括號,`sizeof 變數` 可無括號。
  • `sizeof(指標)` = 4 (32-bit) / 8 (64-bit),**不等於** 所指物件大小。
  • 陣列名在 `sizeof` 下**不退化**為指標:`int a[10]; sizeof(a) == 40`。
  • `&a` 型別為 `int (*)[10]`,`sizeof(&a) == 4/8` (指標大小)。

二、結構體對齊三大規則

  1. **成員偏移**:能被 `min(成員大小, 對齊基數)` 整除。
  2. **總大小**:為 `max(最大成員大小, 對齊基數)` 的倍數,不足尾端填充。
  3. **巢狀結構體**:視為整體,按其自身對齊需求對齊。

struct A { int i; double d; };       // 4 + 4pad + 8 = 16
struct B { int i; struct A a; double d; }; // 4 + 4pad + 16 + 8 = 32

三、字串字面值與指標


char *p = "hello";        // 錯誤:字串字面值唯讀,應為 const char *
const char *p = "hello";  // 正確
char arr[] = "hello";     // 陣列在堆疊,可修改
  • 字串字面值儲存於 **唯讀區** (`.rodata`),修改導致段錯誤。
  • 相同字面值可能合併 (編譯器最佳化),`"abc" == "abc"` 可能為真。

四、指標進階分類

宣告含義可修改項
`const int *p`指向常數整數p ✅, *p ❌
`int *const p`常數指標p ❌, *p ✅
`const int *const p`常數指標指向常數p ❌, *p ❌
`void *p`無型別指標不可算術運算,僅賦值/比較/轉型

五、typedef 陷阱


typedef char *pstr;
const pstr s;   // 展開為 char *const s (常數指標),**非** const char *s

**教訓**:`typedef` 非文字替換,`const` 修飾整個別名實體。

六、函數指標完整語法


/* 回傳 int,參數 (int, double) */
typedef int (*FuncPtr)(int, double);

/* 回傳函數指標的函數 */
int (*get_handler(int cmd))(int, double);

/* 函數指標陣列 */
int (*handlers[10])(int);

/* 指向函數指標陣列的指標 */
int (*(*ph)[10])(int);

**右左法則**:從變數名出發,先右後左,遇括號優先處理。

七、函數參數與呼叫慣例

  • **參數求值順序未定義** (C 標準),嚴禁 `func(i++, i++)` 或 `func(f(), g())` 有副作用。
  • **後置遞增** 在參數中:副作用完成時機**未指定**,不同編譯器結果不同。
  • **預設 `extern`** 連結,檔案內部函數加 `static` 限制連結範圍。
  • **遞迴/靜態區域變數** 破壞函數純粹性,慎用。

八、前置處理器實戰模式

九、頭文件設計原則

  1. **僅含宣告**:型別定義、函數原型、`extern` 變數宣告、宏/內聯函數。
  2. **禁用定義**:非 `static`/`inline` 函數定義、非 `const` 變數定義 → 連結錯誤。
  3. **自包含測試**:頭文件單獨 `#include` 能編譯通過。
  4. **最小依賴**:前向宣告代替包含其他頭文件。

十、常見未定義行為 (UB) 清單

  1. 有號整數溢位
  2. 解參考空指標/野指標
  3. 陣列越界存取
  4. 修改字串字面值
  5. 無序列點雙重修改同一變數 (`i = i++`)
  6. 讀取未初始化區域變數
  7. 無效指標運算 (指向不同物件的指標相減)

結語

C 語言中級門檻在於 **精準掌握型別系統、記憶體模型、指標代數、編譯期/執行期界限、UB 邊界**。將上述十大類知識點內化為肌肉記憶,配合 `-Wall -Wextra -Werror -fsanitize=address,undefined` 日常編譯,即可寫出健壯、高效、可移植的系統級代碼。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
模式範例
編譯期斷言`_Static_assert(sizeof(int)==4, "int_must_be_32bit");` (C11)
字串化`#define STR(x) #x` → `STR(hello)` → `"hello"`
標記連接`#define CAT(a,b) a##b` → `CAT(var,1)` → `var1`
變參宏`#define LOG(...) fprintf(stderr, __VA_ARGS__)`
防重複包含`#pragma once` 或 `#ifndef GUARD_H ... #endif`
條件編譯`#ifdef DEBUG ... #endif`、`#if VERSION > 2`