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

C語言編程經驗積累(三):函數指針、union、內聯、類型提升與 switch 陷阱

     編輯:關於C語言

核心知識點精講

1. 函數指針 typedef 定義

// 定義函數指針類型 PFUN,指向無參無返回值函數
typedef int (*PFUN)();
PFUN pfun; // 聲明變量

// 帶參數版本
typedef unsigned short (*pTaskEventHandlerFn)(unsigned char task_id, unsigned short event);
pTaskEventHandlerFn tasksArr[10]; // 函數指針陣列

技巧:在聲明中用類型名替換變量名,前加 typedef 即得新類型。

2. 陣列初始化可省略大小

int a[] = {2,4,6,8,10}; // 編譯器自動推導大小為 5
static int a1[5] = {1,2,3,4,5};
static int a2[] = {1,2,3,4,5}; // 等價

3. 參數入棧順序

C 語言調用約定(cdecl):參數從右向左壓棧,調用者清棧。棧頂通常為低地址。

4. for 循環執行順序

for (a; b; c) { e; }
// 順序:a → b(判斷) → e → c → b → e → c ... 直到 b 為假

5. union 共用體內存重疊

typedef union {
    uint32_t time32;
    uint16_t time16[2];
    uint8_t  time8[4];
} osalTime_t;
// 所有成員共享同一塊內存,修改任一成員影響其他
// 適用於不同視圖訪問同一數據(如協議解析)

6. inline 內聯函數權衡

  • 優點:消除調用開銷(壓棧、跳轉、恢復),適合短小高頻函數
  • 缺點:代碼膨脹,增加指令緩存壓力;遞歸函數不可內聯
  • 建議:static inline 限制文件內可見,避免多文件重複展開

7. (int*)0 空指針用法

表示地址為 0 的整型指針,通常用於硬件寄存器映射或標記無效指針。不可解引用寫入,讀取可能觸發硬件故障。

8. extern 與 static 鏈接屬性

  • extern:聲明外部定義,跨文件共享(默認函數/全局變量為 extern)
  • static:限制本文件可見,函數/全局變量內部鏈接
  • 頭文件僅放 extern 聲明,定義放在單一 .c 文件

9. offsetof 宏原理

#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE*)0)->MEMBER)
// 利用空指針解引用計算成員偏移,編譯期常量,無運行開銷

10. 32位機單字節訪問機制

讀取:加載 4 字節 → 移位屏蔽取目標字節。寫入:讀取 4 字節 → 修改目標字節 → 寫回 4 字節。編譯器自動生成指令序列,32位對齊訪問最高效。

11. 中斷嵌套與優先級

  • 高優先級中斷可搶佔低優先級
  • 同級中斷:當前處理完成前不響應新同級中斷(硬件自動屏蔽)
  • 未完成服務程序時,同源中斷掛起

12. switch-case 穿透陷阱

switch (cmd) {
    case 1: do_a(); break;
    case 2: do_b(); // 缺少 break!
    case 3: do_c(); // case 2 會穿透執行 do_c()
    default: do_d();
}
// 利用穿透實現多值同邏輯:
case 1: case 2: case 3: handle_123(); break;

13. 邏輯非 ! vs 位非 ~

!1 == 0; !0 == 1; !5 == 0; // 非零變 0,零變 1
~1 == -2 (0xFFFFFFFE); // 逐位翻轉

14. 宏定義無符號後綴

#define VAL 0x00000001u  // u: unsigned int
#define VAL 0x00000001UL // UL: unsigned long (32位)
#define VAL 0x00000001ULL // ULL: unsigned long long (64位)

15. 陣列指針 vs 指針陣列

int (*a)[10]; // 陣列指針:指向 10 個 int 的陣列
int *a[10];   // 指針陣列:10 個 int* 指針

16. Windows 路徑轉義

"C:\\Users\\Name\\file.txt" // 雙反斜杠或單正斜杠 "C:/Users/Name/file.txt"

17. printf %#x 替代形式

%#x → 0x前綴; %#o → 0前綴; %#d → 無變化

18. 靜態變量初始化限制

靜態/全局變量初始值必須為編譯期常量(常數、宏常量、const 常量),不可用變量初始化。運行時可賦值變量。

19. assert 斷言

assert(ptr != NULL); // 條件為假時終止程序,輸出文件行號,Debug 模式生效

20. 4字節對齊計算

aligned = (bytes + 3) & ~3; // (bytes+3) & 0xFFFFFFFC
// 或 aligned = ((bytes + 3) >> 2) << 2;

21. for 循環 break 與自增

break 直接跳出循環體,i++ 不執行。

22. 指針與靜態陣列 sizeof

int *p; sizeof(p) = 4/8 (指針大小)
int a[10]; sizeof(a) = 40 (陣列總大小)
void func(char p[]) { sizeof(p) = 4/8; } // 參數退化為指針

23. 複合賦值運算符

a *= b; a += b; a |= b; a &= b; a ^= b; // 等價 a = a op b
// 注意:a = ~a 是按位取反,非取負

24. volatile 關鍵字

  • 告知編譯器:該變量可能被硬件/中斷/其他線程意外修改
  • 禁止優化為寄存器讀寫,每次強制內存訪問
  • 典型用途:硬件寄存器映射、中斷標誌位、多線程共享標誌

25. 位域結構

typedef union {
    unsigned char value;
    struct {
        unsigned int bit0:1; ... bit7:1;
    } bit_field;
} PORT;
// 每位獨立訪問,節省空間,硬件寄存器操作常用

26. fstat/ftruncate 文件操作

fstat(fd, &st); // 獲取文件大小 st.st_size
ftruncate(fd, new_len); // 截斷/擴展文件
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved