另一個人們依賴的未文檔化行為:輸出緩沖區
對于一個通過輸出緩沖區來返回數據的函數,如果函數執行失敗,則這個緩沖區里的數據是未定義的,調用者不應該對這些數據做出任何假定。
但是,還是有人會這樣做。
我曾經讀過 Michael Kaplan 的一篇關于輸出緩沖區的文章,在那篇文章中,用戶要求,即使函數執行失敗,函數也需要將輸出緩沖區里的數據做出一定的設置后才返回。
為什么輸出緩沖區在函數失敗的時候一定不能做出任何修改,因為有很多應用程序會依賴這個行為:函數調用失敗后,函數將不會對輸出緩沖區做任何改動,即使并沒有文檔指明函數一定要支持這個行為特征。
下面是一個簡化版本的例子代碼,它會依賴輸出緩沖區在函數調用失敗后不會有任何改動。
此代碼片段首先定義一個默認的注冊表鍵值,然后嘗試打開一個”更好”的鍵,假設如果打開失敗,hk 變量的內容將保持不變,因此將繼續具有原始默認值。RegOpenKeyEx 函數的規范不能保證這種行為,但這并不能阻止人們依賴它。
這只是 Win32 為了兼容性而需要定期維持的各種濫用行為的一個簡單示例。因為,畢竟,人們購買計算機是為了在計算機上運行程序。
“失敗時輸出緩沖區未定義”規則的一個重要例外是 COM 接口返回的輸出緩沖區規則是,輸出緩沖區始終被初始化,即使在失敗時也是如此。這對于確保編組器不會崩潰是必要的。例如,IUnknown::QueryInterface 方法的最后一個參數必須在失敗時設置為 NULL。
總結
到底要不要設置輸出緩沖區,好像確實是一個需要權衡的問題。
如果代碼庫作者決定在函數執行失敗的時候設置緩沖區,則必須在文檔中明確指明此行為。
我的個人習慣是:不論函數是否執行成功,都會在客戶提供的緩沖區設置一個合理值。
說到底,我看起來還是一個決定論者。
最后
Raymond Chen的《The Old New Thing》是我非常喜歡的博客之一,里面有很多關于Windows的小知識,對于廣大Windows平臺開發者來說,確實十分有幫助。
本文來自:《More undocumented behavior and the people who rely on it: Output buffers》