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

C語言拾遺:const、volatile、柔性陣列、貪婪解析、預處理宏技巧

     編輯:關於C

前言

C語言角落裡藏著幾個強大但常被忽視的特性。本文深度解析 const 編譯器優化與 typedef 交互、volatile 記憶體屏障語義、C99 柔性陣列成員機制、編譯器詞法分析的「貪婪法則」、實用預處理指令(#line, #error)與預定義宏,助你駕馭這些進階武器。

一、const:不只是「只讀」

1. 編譯器優化:符號表常量傳播

  • const int MAX = 100; 編譯器通常**不分配存儲空間**,直接置入符號表,作為編譯期常量傳播,消除記憶體讀取,效率等同 #define MAX 100。
  • 與宏差異:const 有**型別**、**作用域**、**地址**(若取址則會分配存儲),除錯器可見;宏無型別、文本替換、多份拷貝。

2. const + typedef 陷阱


typedef struct Student *StuPtr;
const StuPtr p1;  // 等價 StuPtr const p1 → struct Student *const p1 (常量指針)
StuPtr const p2;  // 同上

規則:const 修飾的是**變數本身**(指針變數),而非 typedef 別名代表的型別。typedef **不進行文本展開**,而是被視為一個不可分割的型別標識符。

二、volatile:告訴編譯器「這裡有外部魔法」

  • 修飾變數表示:其值可能被**編譯器未知因素**改變(硬體寄存器、中斷服務程式、其他執行緒、信號處理器、記憶體映射 I/O)。
  • 效果:編譯器**禁用所有優化**(常量傳播、死碼消除、重排序、暫存器快取),**每次訪問強制讀寫記憶體**。
  • 典型場景:volatile uint32_t *GPIO_ODR = (uint32_t*)0x40020014; 硬體寄存器映射。
  • 注意:volatile **不提供原子性、不提供記憶體屏障、不保證執行緒可見性**!多執行緒同步請用 atomic (C11) / pthread_mutex / 平台原子操作。

三、柔性陣列成員(C99,GCC 擴充支援 C90)

1. 語法與規則


struct Line {
    int length;
    char contents[]; // 無長度陣列,必須是結構體**最後一個**成員
};
  • 結構體大小 不包含 柔性陣列(sizeof(struct Line) == sizeof(int))。
  • 分配時一次性申請:struct Line *p = malloc(sizeof(struct Line) + n);。
  • 前面**至少有一個**非柔性成員。
  • 包含柔性陣列的結構體**不能**作為陣列元素、其他結構體成員(除非是聯合的最後一個成員)。

2. C90 替代寫法


struct Line90 { int length; char contents[0]; }; // GCC/Clang 支援零長度陣列
struct Line90_alt { int length; char contents[1]; }; // 經典「結構體黑客」,需手動 -1 分配

四、詞法分析貪婪法則:a+++b 如何解析?

  • 規則:**最大吞噬**——從左到右,盡可能構成最長的合法預處理符號/詞法單元。
  • a+++b → a ++ + b(a++ 合法,a+++ 非法)→ (a++) + b。
  • a---b → a -- - b → (a--) - b。
  • 實務建議:**加空格、加括號**消除歧義:(a++) + b。

五、實用預處理指令

指令作用範例
#line改變編譯器報告的行號/檔名#line 100 "my_gen.c" 生成代碼調試用
#error強制編譯錯誤並輸出訊息#error "Unsupported platform!"
#pragma編譯器特定指示(對齊、優化、訊息抑制)#pragma pack(1) #pragma GCC diagnostic ignored "-Wunused"

六、標準預定義宏


__LINE__   // 當前行號 (int)
__FILE__   // 當前檔名 (string literal)
__DATE__   // 編譯日期 "Mmm dd yyyy"
__TIME__   // 編譯時間 "hh:mm:ss"
__STDC__   // 是否符合標準 C (1/0)
__STDC_VERSION__ // C 版本: 199409L(C90), 199901L(C99), 201112L(C11), 201710L(C18)
__func__   // 當前函數名 (C99, 靜態字串)

應用:日誌宏 #define LOG(fmt,...) printf("[%s:%d] " fmt, __FILE__, __LINE__, ##__VA_ARGS__)。

七、總結

掌握 const 編譯期常量傳播與 typedef 交互規則、volatile 硬體/並發邊界語義、柔性陣列動態結構體模式、貪婪法則避坑、預處理宏診斷能力,能讓你在嵌入式、系統級、高效能 C 開發中遊刃有餘。

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