C語言看似簡單,但型別系統、變數定義、存儲類別暗藏許多易踩的坑。本文匯總 12 個實戰小貼士,涵蓋 char 符號性、字元編碼、sizeof 型別、常數後綴、C99 迴圈變數、自動變數生命週期、register 限制,助你寫出更標準、可移植的代碼。
char 符號性由實現定義signed/unsigned 修飾的 char,**是否帶符號完全取決於編譯器/平台**(ARM常預設 unsigned,x86常預設 signed)。signed char 或 unsigned char;僅存儲字元時用 char。
char ch = 'a';
printf("%c %d", ch, ch); // 輸出: a 97
char 本質是足夠容納基本執行字元集的整數型別,字面常數 'a' 編譯期即轉為整數值 97。
字元比較 'a' < 'b' 實際比較其編碼整數值。ASCII 兼容字元集中,數字 < 大寫字母 < 小寫字母。
sizeof 返回型別是 size_tsize_t 保證為無符號整數(通常 unsigned int 或 unsigned long),具體寬度平台相關。| 常數形式 | 預設型別 | 備註 |
|---|---|---|
| 無後綴整數 | int → long → long long | 值超出範圍自動升級 |
| 無後綴浮點數 | double | 3.14 是 double,3.14f 才是 float |
| 後綴 U/u | 無符號對應型別 | 123U |
| 後綴 L/l | 長整型對應型別 | 123L |
| 後綴 F/f | float | 3.14f |
for 迴圈初始化宣告變數
// C99 / C11 / C18 合法
for (int i = 0; i < n; i++) { ... }
// 變數作用域僅限於 for 迴圈區塊
// ANSI C (C89) 不允許,需在迴圈外宣告
register 變數無法取址
register int fast_var = 10;
// int *p = &fast_var; // 編譯錯誤:register 變數無地址
register 關鍵字多被忽略(視為提示),不建議手動指定。offsetof
#include
struct Demo { char c; int i; double d; };
printf("c offset: %zu\n", offsetof(struct Demo, c)); // 0
printf("i offset: %zu\n", offsetof(struct Demo, i)); // 4 (對齊)
printf("d offset: %zu\n", offsetof(struct Demo, d)); // 8 (對齊)
printf("sizeof: %zu\n", sizeof(struct Demo)); // 24 (填充)
struct Flags { unsigned a:1; unsigned b:3; unsigned c:4; };
// int *p = &flags.a; // 錯誤:位欄無地址
// 位欄順序(高位在前/低位在前)由實現定義,跨平台慎用
restrict 關鍵字 (C99) 幫助編譯器優化
void copy(int *restrict dst, const int *restrict src, int n) {
// 告訴編譯器 dst 和 src 不重疊,可激進向量化/重排
for (int i = 0; i < n; i++) dst[i] = src[i];
}
int32_t/uint8_t 等定寬型別(<stdint.h>),避免 int/long 寬度不定。char,位元組操作用 uint8_t,字串用 char*。123U, 3.14f),避免隱式轉換驚喜。-Wconversion -Wsign-compare -Wsizeof-pointer-memaccess 捕捉型別陷阱。