2017-03-21 22 views
19

在我的一個大學項目中,我得到了分數和我的教授的反饋,說我沒有處理printf錯誤。檢查printf的返回值是否重要?

在英語 - >/ * ### FB: Error handling printf() is missing * /

/* ### FB: Fehlerbehandlung printf() fehlt */ 
    printf("%7lu %8lld %10s %3lu %-8s %-8s %8lu %12s %s %s %s\n", 
      sb->st_ino, nblks, permstr, (unsigned long) sb->st_nlink, 
      username, groupname, sb->st_size, 
      ntime, filename, (symlink ? "->" : ""), 
      (symlink ? symlink : "") 
      ); 

我的問題是,是不是真的很重要要經常檢查printf函數的返回值和處理錯誤?即使我發現錯誤,我仍然會使用fprintf打印到stderr,對此我必須再次檢查fprintf的返回類型。

那麼什麼時候應該檢查返回值,以及如何處理?

+26

IMNVHO你的教授是個白癡。 –

+0

問你的老師爲什麼他認爲這很重要。我從來沒有見過任何產品代碼檢查返回值,並且從來沒有使用過它。你究竟應該怎樣處理呢? Paul R.說的。 ;) – Devolus

+1

對此的第一個答案可能是有用的http://stackoverflow.com/questions/13535557/why-does-printf-return-a-value – Orangesandlemons

回答

14

一般來說,您應該始終檢查函數的返回值是否有錯誤。

然而,在printf的情況下,在大多數情況下這樣做幾乎沒有用處。正如你所提到的,如果它確實失敗了,你可以使用fprintf來打印到stderr,但是這就提出了應該檢查錯誤的問題。

如果您不重定向或重新打開stderr您可能會遇到同樣的問題,在這種情況下,這可能無所謂,但如果stderr指向其他位置,則寫入時可能會有價值。您也可以退出流程,但您需要確定這樣做是否合理。

您可能想要檢查返回值的一個值得注意的時間是如果您想跟蹤爲打印格式而打印的字符數。我在寫入日誌文件以確定何時滾動日誌時使用fprintf,但由於printf通常寫入交互式控制檯(如果它不是由於重定向導致的,您不會知道它),因此,真的很適用。

至於你的教授,我唯一的猜測是他希望你養成檢查錯誤的習慣。這是一件好事,但大多數規則都有例外,這就是其中之一。

+8

如果printf()失敗,你該怎麼辦?您可以中止線程或進程,並且在某些情況下可能會這樣做。還有其他的可能性。此外,如果您選擇發出錯誤消息(這不一定是個壞主意),那麼適當的流是'stderr',並且沒有理由認爲只是因爲printf()(到'stdout')失敗,'fprintf(stderr,...)'將不起作用。 –

+0

@JohnBollinger但是,除非將這些情況指定爲問題/任務的一部分,否則期望「大學項目」考慮「printf」失敗的可能性可能是不合理的。 – TripeHound

+3

@TripeHound,相反,如果適用的指令要求*所有*錯誤被識別和處理,那麼我認爲沒有理由排除'printf()'產生的錯誤。此外,我在嚴格執行這樣的約束時看到了一些迂腐價值,並不是因爲具體的'printf'的細節,而是因爲理解如何符合詳細說明的一般重要性。此外,還有一點可以使人們認識到,計算機不會做出那種建議對'printf()'進行例外處理的價值判斷。 –

10

爲了清楚起見 - printf()返回...

printf該函數返回,如果發生了輸出或編碼誤差發送的字符數,或爲負值。 C11§7.21.6.33


檢查的printf()的返回值而負值pedantic,並且通常不需要。人們可以考慮以下情況:


環境限制

單個printf()"%s"可能會超過環境限制並導致printf()返回負值。這並不意味着fprintf(stderr, ...的後續消息也必須失敗。

可以由任何單一的轉換來產生至少應爲4095 C11§7.21.6.115


弱輸出裝置的字符數。

已知知道stdout經常被重定向到需要檢測輸出故障的通信接口的情況。儘管屏幕輸出成功非常高,但對於串行(rs232)等其他各種輸出流來說並非如此。在這種情況下,stdoutstderr可能會有不同的重定向,因此stderr可能會保持可靠。


在任何情況下,如果曲線上的教授檔次,有可能招致許多相同的負端 - 所以沒有年級差異。使用具有奇怪要求和期望的客戶。

+4

當stdout是一個串行端口時,大多數時候您將會斷開SIGHUP。爲了將其轉換爲來自printf的EIO錯誤,您需要明確地忽略SIGHUP;默認的操作是終止進程,並在一些其他適當的操作的應用程序中,安裝信號處理程序是正常的。類似的觀察適用於SIGPIPE,另一種可能的標準輸出失敗原因。 – rici

+2

'+(int)(M_PI/3)'爲最後一句。釘在棺材上。 – vaxquis

+1

FWIW,我嘗試了用gcc打印一對2,000,000,000字符的字符串(+ \ 0)與'int n = printf(「%s%s \ n」,buf,buf);'結果是期望的文本和-294,967,294或-4,000,000,002 - (UINT_MAX + 1))的負返回值) - 因此該平臺上的錯誤指示符並不多。 – chux

3

不檢查返回值被認爲是不好的做法。但它被認爲是乾淨的,如果你明確的指出你忽略的返回值加上(void)盈函數調用的:

(void) printf(...); 

這表明,你知道有返回值,但你是有意忽視它。

+2

不可以。將一個返回值轉換爲'void'表示您有意忽略它,這是一種抑制診斷的機制。這是醜陋的,冗長的,並可能令人困惑。它也決定* un * clean,因爲它隱藏了問題而不是修復它。 –

+4

@JohnBollinger與_not_轉換結果相比,這意味着「我忘了這個函數返回任何東西,並且可能因爲它而在我的代碼中存在一個錯誤」。清潔劑究竟如何?明確的轉換意味着「我知道這個函數返回一些東西,但我不在乎」。在printf的情況下,它可能不會返回任何有意義的東西。如果它不是這樣一個可怕的函數,它會返回不正確的格式字符串等錯誤,但我從來沒有看到實際上這樣做的實現。 – Lundin

+0

@Lundin,如果你在第一時間充分考慮到將問題轉換爲「無效」的問題,那麼就簡單地*評論*你清楚地知道你忽略了返回值這一事實是更清潔的。這進一步讓你有機會說出爲什麼你忽略它。 –

2

Unix的哲學是stdout(儘管不一定stderr)應該是可以進一步處理的。編譯器和生成器使用它來輸出代碼。 stdout應該是您的過程產品的地方。如果該產品被縮短,您的流程不應該返回EXIT_SUCCESS。 我說要檢查那些寫入到stdout。另一方面,爲了方便起見,或多或少,如果你使用它,那麼你可能已經處於錯誤狀態,如果你的錯誤報告失敗了,你就沒有多少(儘管你仍然應該用返回碼來指示錯誤)。)

+0

@Dmitri在這種情況下,如果寫入器捕獲任何信號,'printf'可能會從'EINTR'失敗。否則,它不會失敗,AFAIK(只要操作系統和讀者都可以)。如果你使用普通文件作爲媒介('>'rediction),那麼IO錯誤是可能的。 – PSkocik

0

不是。在現實世界中,與文化中的學術運動相反mit einem RuffürPedanterie,檢查返回並不重要printf()close()的值,或者其他一些事情。如果沒有合理的方式來處理信息,爲什麼要收集信息呢?

+0

Djb是迂腐。但我同意他說,檢查printf返回值是非常好的做法https://news.ycombinator.com/item?id=9155741 – yota