呼叫慣例(__cdecl/__stdcall/__fastcall)、DLL 匯出入(__declspec(dllexport/import))、語言連結(extern "C")**僅需在標頭檔宣告**,實作檔不必重複。
C99 前常見寫法(結構體尾端宣告長度為 1 的陣列),配合 malloc(sizeof(Struct)-1 + len) 實現變長結構體:
struct Name {
int len;
char str[1]; // 柔性數組成員 (C99 標準寫法為 char str[])
};
struct Name* make_name(const char* s) {
struct Name* p = malloc(sizeof(struct Name) - 1 + strlen(s) + 1);
if (p) {
p->len = (int)strlen(s);
strcpy(p->str, s);
}
return p;
}
優點:單次分配、記憶體連續、快取友好。缺點:依賴編譯器不對結構體尾端填充、非標準 C89 行為(C99 已標準化為 char str[])。
(int[]){5} 產生臨時陣列並取得指標,可直接傳遞給 void f(int*),類似 Java 匿名陣列。struct S s = {.a=1, .b=2};、int a[10] = {[5]=99};。inline 關鍵字正式進入標準(C99),但編譯器可選擇忽略。void f(int n) { int a[n]; }(C11 改為選擇性支援)。struct Demo {
char c; // offset 0
int i; // offset 4 (假設 4 位元組對齊)
short s; // offset 8
}; // sizeof = 12 (尾端填充至 4 的倍數)
offsetof(T, m) (需 <stddef.h>);非標準手寫版:#define OFFSET(T,m) ((size_t)&(((T*)0)->m))。== 比較結構體:填充位元組內容不定,導致誤判。需逐欄位比較或 memcmp(後者同樣受填充干擾)。void f(int*) 傳入常數:C99 使用複合字面量 f((int[]){42});C89 需建立暫存變數。void(*)() vs void*)。() 是函式指標唯一的後綴運算子。NULL 定義為 0、0L 或 (void*)0;某些架構(如段式記憶體)以特殊位模式實現 NULL 以觸發硬體陷阱捕捉空指標解參考。0 或 NULL 等價。f((int*)0) 或 f((void*)NULL)。'\0'、整數 0)請勿使用 NULL。a[i] ≡ *(a + i) ≡ i[a]。陣列非一級物件,下標運算子建立在指標運算之上。透過不同型別指標(int (*)[N] vs int*)可實現不同粒度的 ++/-- 重載。
《C Programming FAQs》 (Steve Summit, 人民郵電出版社 2008) — 習題式涵蓋上述所有細節與更多陷阱,案頭必備。