作者編寫 HTTP 下載工具,需跨平台創建臨時文件。Unix 下 tmpfile() 正常,Windows 下卻在 C:\ 創建文件(需管理員權限),導致失敗。於是寫了跨平台封裝:
#ifdef _WIN32
#define tmpfile w32_tmpfile
#endif
FILE* w32_tmpfile(void) { /* Windows 實現 */ }
調用處使用三元運算符:
g = fname ? fopen(fname, "w+") : tmpfile();
編譯通過,運行卻**不調用** w32_tmpfile。改用 if-else 卻正常。經過漫長調試,最終發現罪魁禍首在註釋:
/* Write new file (plus allow reading once we finish) */
// FIXME Win32 native version fails here because
// Microsoft's version of tmpfile() creates the file in C:\
g = fname ? fopen(fname, "w+") : tmpfile();
註釋最後一行 C:\ 結尾的反斜杠 \ 在 C/C++ 中代表「行繼續」,導致下一行代碼也被視為註釋一部分!
因為作者在修改時**註釋掉了**原三元運算符那行:
// FIXME ... C:\
//g = fname ? fopen(fname, "w+") : tmpfile(); ← 這行被吞了沒關係
if (NULL != fname) { ... } ← 新代碼在註釋外,正常編譯
float result = num/*pInt;
...
/* some comments */
num++;
意圖寫 num / *pInt,但漏了空格導致 /* 開啟註釋,一直持續到 */,中間代碼全「消失」。
C:/、C:\\、原始字符串 R"(C:\)"。-Wcomment、MSVC /W4 會提示「註釋中的反斜杠新行」。g = fname ? fopen(...) : (tmpfile()); 縱使被吞也只影響該表達式,不影響後續邏輯(但仍會編譯錯誤)。這個 Bug 堪稱「愚蠢」是因為它**極其隱蔽、極其低級、極其浪費時間**。每個 C/C++ 程序員都應在職業生涯早期栽一次這個跟頭,然後永遠記住:**註釋也是代碼的一部分,請像對待代碼一樣審視它們。**