for (i = count - 1; i >= 0; i--) {
if ((ULong)memblock == (ULong)(pMemInfo[i].addr)); // ← 這裡多了一個分號!
{
fprintf(pf, "nAllSize = %u\n", pMemInfo[count-1].nSizeAll);
pMemInfo[count-1].nSizeAll -= pMemInfo[i].nSize;
break;
}
}
在 C/C++ 中,if (condition); 是一條空語句 (null statement)。編譯器將其視為:
if ((ULong)memblock == (ULong)(pMemInfo[i].addr))
; // 空操作,什麼都不做
{ // 這是一個獨立的區塊語句,與 if 無關!
fprintf(...);
pMemInfo[count-1].nSizeAll -= pMemInfo[i].nSize;
break;
}
後果:大括號內的代碼無條件執行,break 導致迴圈在第一次迭代就跳出,嚴重偏離原本「找到匹配項才處理」的邏輯。
-Wempty-body 或 Clang Static Analyzer 會警告)。if。// 推薦:即使單行也加大括號
if (condition) {
do_something();
} else {
do_other();
}
若誤加分號:if (condition); { ... },編譯器會報錯 “else without previous if”,直接暴露錯誤。
# GCC/Clang
-Wempty-body -Wextra -pedantic
# MSVC
/w4 (包含 C4390: empty controlled statement)
配合 -Werror 將警告視為錯誤,編譯階段即攔截。
使用 clang-format 或 uncrustify 統一風格,CI 流程中強制檢查:
.clang-format 關鍵設定:
BreakBeforeBraces: Allman // 或 Stroustrup
AllowShortIfStatementsOnASingleLine: false
AllowShortBlocksOnASingleLine: false
// 原始深層巢狀
for (i = count - 1; i >= 0; i--) {
if (match) {
handle();
break;
}
}
// 重構:提前返回/繼續,減少縮排
for (i = count - 1; i >= 0; i--) {
if (!match) continue; // 衛語句
handle();
break;
}
| 代碼模式 | 問題 | 修正 |
|---|---|---|
for (i=0; i<n; i++); { ... } | 迴圈體空跑,大括號只執行一次 | 移除分號 |
while (getchar() != '\n'); | 故意清空緩衝區,但易誤讀為空迴圈 | 加註釋 /* intentional */ 或改用 do { } while(...) |
if (x = y); // 應為 == | 賦值+空語句,x 被修改且後續區塊無條件執行 | 啟用 -Wparentheses,習慣寫 if (CONST == var) |
「if 後多一個分號」 是 C/C++ 最隱蔽且破壞力強的語法陷阱之一。透過強制大括號、編譯器警告、靜態分析、自動格式化 四層防線,可將此類錯誤在編碼階段徹底消除。養成「永不寫裸露的單行控制語句」習慣,是寫出健壯 C 代碼的基石。