「C 語言中怎樣的變數名才是合法的?」這看似基礎,實則關係到程式碼可讀性、跨平台相容性、維護成本。本文依據 C 標準 (C99/C11/C17/C23),結合業界最佳實踐 (MISRA C, CERT C, Linux Kernel Coding Style),為您整理完整的命名規則、推薦慣例與避坑指南。
| 規則編號 | 規則內容 | 標準依據 | 違反後果 |
|---|---|---|---|
| 1 | 僅能包含字母 (A-Z, a-z)、數字 (0-9)、底線 (_) | C99 §6.4.2.1 | 編譯錯誤:invalid character |
| 2 | 首字元不能是數字 (可為字母或底線) | C99 §6.4.2.1 | 編譯錯誤:expected identifier |
| 3 | 不能是關鍵字 (32 個 C89 關鍵字 + C99/C11 新增:_Bool, _Complex, _Imaginary, inline, restrict, _Alignas, _Alignof, _Atomic, _Generic, _Noreturn, _Static_assert, _Thread_local) |
C99 §6.4.1 | 編譯錯誤:expected declaration specifiers |
| 4 | 區分大小寫:count, Count, COUNT 為三個不同識別字 |
C99 §6.4.2.1 | 邏輯錯誤:誤用導致難以發現的 Bug |
| 5 | 無長度上限 (C99 要求編譯器支援至少 63 字元外部識別字、31 字元通用識別字;現代編譯器通常支援 4096+) | C99 §5.2.4.1 | 舊編譯器可能截斷導致名稱衝突 |
| 6 | 保留識別字不可用: • 以雙底線開頭 ( __foo)• 以下底線 + 大寫字母開頭 ( _Foo)• 以底線開頭後接大寫字母的標準庫內部名稱 |
C99 §7.1.3 | 未定義行為:與編譯器/標準庫內部符號衝突 |
/* C89 (32) */ auto break case char const continue default do double else enum extern float for goto if int long register return short signed sizeof static struct switch typedef union unsigned void volatile while /* C99 (5) */ _Bool _Complex _Imaginary inline restrict /* C11 (7) */ _Alignas _Alignof _Atomic _Generic _Noreturn _Static_assert _Thread_local /* C23 (1) */ constexpr
| 識別字類別 | Linux Kernel / C 標準庫風格 | MISRA C / 嵌入式風格 | Windows API / Microsoft 風格 | 說明 |
|---|---|---|---|---|
| 區域變數/參數 | snake_case : int user_count |
snake_case + 前綴型別 : uint16_t u16UserCount |
camelCase : int userCount |
最常用,統一專案風格即可 |
| 全域變數 | g_snake_case 或 snake_case (模組靜態) |
g_snake_case : int32_t g_s32TotalCount |
g_camelCase 或 m_camelCase (類成員) |
建議加 g_ 前綴區分作用域,減少副作用 |
| 常數/巨集/列舉值 | UPPER_SNAKE_CASE : #define MAX_BUFFER_SIZE 1024 |
UPPER_SNAKE_CASE : enum { STATE_IDLE, STATE_RUN } |
UPPER_SNAKE_CASE : #define MAX_PATH 260 |
巨集必全大寫,防止與函式混淆 |
| 函式名稱 | snake_case : void calculate_sum(int a, int b) |
PascalCase 或 snake_case + 模組前綴 : Uart_SendByte() |
PascalCase : void CalculateSum(int a, int b) |
動詞開頭,語義清晰:get_, set_, is_, handle_, init_, cleanup_ |
| 結構體/聯合體/列舉標籤 | snake_case : struct user_info |
PascalCase : struct UserInfo |
PascalCase : struct USER_INFO (C 風格常全大寫) |
配合 typedef 簡化宣告 |
| 型別別名 | _t 後綴 : typedef uint32_t u32; (標準庫 size_t, pid_t) |
_t 後綴 + 前綴 : typedef uint16_t U16; |
無固定後綴,常用 DWORD, HANDLE, LPVOID |
標準庫保留 _t 後綴,自定義避免衝突 |
/***** 絕對禁止 *****/
int __private = 0; // 雙底線開頭:編譯器保留
int _Internal = 0; // 底線+大寫:編譯器保留
int _Alignas = 0; // 標準庫保留關鍵字模式
/***** 建議避免 *****/
int _count = 0; // 單底線開頭:標準庫內部常用,雖合法但易衝突
int _t = 0; // _t 後綴:POSIX/標準庫型別慣例
/***** 安全示範 *****/
int count = 0;
int user_count = 0;
int g_total_users = 0;
static int s_module_state = 0; // 檔案域靜態
int Count = 10;
int count = 20;
printf("%d\n", Count); // 10
printf("%d\n", count); // 20
// 易誤寫為 count/Count 導致邏輯錯誤,建議專案統一風格
#define MAX 100
// 若其他頭檔也定義 MAX,會衝突
// 建議加專案/模組前綴
#define MYAPP_MAX_BUFFER 1024
#define NET_MAX_PACKET 1500
i, j, k 僅限迴圈索引;p, q 僅限指標暫存。其他場合禁用單字母。int the_total_number_of_registered_users_in_the_system = 0; 降低可讀性。建議 int total_registered_users = 0;。# .clang-format
BasedOnStyle: LLVM
IndentWidth: 4
ColumnLimit: 120
NamingStandard: CamelCase # 或自訂
# 強制特定類別命名風格 (需 clang 15+)
NamingRules:
- Regex: '^g_.*'
Style: snake_case
- Regex: '^s_.*'
Style: snake_case
- Regex: '^[A-Z_]+$'
Style: UPPER_SNAKE_CASE
- Regex: '^_[A-Z]'
Style: snake_case # 禁止保留識別字模式
合法變數名只是底線,良好的命名慣例才是專業程式設計師的簽名。遵循標準規範、統一專案風格、語義化命名、善用靜態分析工具強制檢查—— 這樣的程式碼,不僅編譯器能過,同事讀起來順暢,六個月後的自己維護時也能「秒懂」。從今天開始,給每個變數一個清晰、精確、一致的名字,這是寫出高品質 C 程式碼的第一步。