避免對任何資料結構的長度或數量設定任意限制,包括檔案名稱、行、檔案和符號,方法是動態分配所有資料結構。在大多數 Unix 工具程式中,「長行會被靜默截斷」。這在 GNU 工具程式中是不可接受的。
讀取檔案的工具程式不應丟棄 NUL 字元,或任何其他非列印字元。程式應正確處理多位元組字元編碼,例如 UTF-8。您可以使用 libiconv 來處理各種編碼。
檢查每個系統呼叫是否有錯誤返回,除非您知道您想要忽略錯誤。在每個因系統呼叫失敗而產生的錯誤訊息中,都應包含系統錯誤文字(來自 strerror
或等效函數),以及檔案名稱(如果有的話)和工具程式名稱。僅僅「無法開啟 foo.c」或「stat 失敗」是不夠的。
檢查每次呼叫 malloc
或 realloc
,看看它是否返回 NULL
。即使您縮小區塊,也要檢查 realloc
;在將區塊大小四捨五入為 2 的冪的系統中,如果您要求較小的空間,realloc
可能會取得不同的區塊。
您必須預期 free
會更改已釋放區塊的內容。任何您想要從區塊中獲取的內容,都必須在呼叫 free
之前獲取。
如果 malloc
在非互動式程式中失敗,請將其設為致命錯誤。在互動式程式(從使用者讀取命令的程式)中,最好中止命令並返回命令讀取迴圈。這允許使用者終止其他程序以釋放虛擬記憶體,然後再次嘗試該命令。
使用 getopt_long
來解碼引數,除非引數語法使其不合理。
當靜態儲存區要在程式執行期間寫入時,請使用顯式的 C 程式碼來初始化它。這樣,重新啟動程式(無需重新載入)或程式的一部分,將重新初始化這些變數。保留 C 初始化宣告給不會被更改的資料。
盡量避免使用低階介面來存取晦澀的 Unix 資料結構(例如檔案目錄、utmp 或核心記憶體的佈局),因為這些介面不太可能相容地工作。如果您需要找到目錄中的所有檔案,請使用 readdir
或其他高階介面。這些介面受到 GNU 的相容性支援。
建議的訊號處理機制是 signal
的 BSD 變體和 POSIX sigaction
函數;替代的 USG signal
介面是一種較差的設計。
如今,使用 POSIX 訊號函數可能是使程式具有可移植性的最簡單方法。如果您使用 signal
,那麼在執行 GNU libc 版本 1 的 GNU/Linux 系統上,您應該包含 bsd/signal.h 而不是 signal.h,以便獲得 BSD 行為。是否要支援 signal
僅具有 USG 行為的系統,或放棄對它們的支援,取決於您。
在偵測到「不可能」條件的錯誤檢查中,直接中止程式。通常沒有必要列印任何訊息。這些檢查表明存在錯誤。任何想要修復錯誤的人都必須閱讀原始碼並執行除錯器。因此,請在原始碼中使用註解來解釋問題。相關資料將在變數中,這些變數很容易使用除錯器檢查,因此沒有必要將它們移動到其他地方。
不要使用錯誤計數作為程式的退出狀態。那樣行不通,因為退出狀態值被限制為 8 位元(0 到 255)。程式的單次執行可能會有 256 個錯誤;如果您嘗試返回 256 作為退出狀態,父程序將看到 0 作為狀態,並且會顯示程式已成功。
如果您建立暫存檔,請檢查 TMPDIR
環境變數;如果該變數已定義,請使用指定的目錄而不是 /tmp
。
此外,請注意在全域可寫入目錄中建立暫存檔時,可能存在安全性問題。在 C 語言中,您可以透過以下方式建立暫存檔來避免此問題
fd = open (filename, O_WRONLY | O_CREAT | O_EXCL, 0600);
或者使用來自 Gnulib 的 mkstemps
函數(請參閱 mkstemps in Gnulib)。
在 bash 中,使用 set -C
(長名稱 noclobber
)來避免此問題。此外,mktemp
工具程式是從 shell 腳本建立暫存檔的更通用解決方案(請參閱 mktemp invocation in GNU Coreutils)。