2010-07-08 94 views
1

以下程序是否爲有效的C程序?C標準庫轉角箱

#include <stdio.h> 

int main() 
{ 
    fwrite("x", 1, 1, stderr); 
    fflush(stderr); 
    fgetc(stderr); 
    fwrite("y", 1, 1, stderr); 
    return 0; 
} 

請注意,我嘗試從stderr讀取。

當我編譯它在Visual C++ 2008,並運行它,我得到以下的輸出:

xy 

這是有道理的。但是,當我將stderr重定向到一個文件(test.exe 2> foo.txt)時,我得到一個 「Debug Assertion Failed」窗口,並顯示消息:「流連續數不一致,在連續讀取和寫入之間刷新」。在讀取和寫入之間添加fflush確實解決了問題。 (這發生在調試版本中,在發佈版本中,第二次寫入會靜默失敗)。

這種行爲是否正確,或者這是一個 編譯器 庫錯誤?讀取或寫入的C.是非法的,當我找不到任何地方的任何描述規則

+4

從輸出流中讀取是未定義的行爲。你究竟期望它做什麼? – 2010-07-08 18:50:56

+1

請注意,它不會是一個編譯器錯誤,而是一個庫實現錯誤。 – 2010-07-08 18:52:35

+1

@NeilButterworth - 我不相信讀輸出流應該會導致UB。根據Opengroup的說法,這隻會導致'fgetc'失敗並將errno設置爲'EBADF'(請參閱http://www.opengroup.org/onlinepubs/009695399/functions/fgetc.html) – 2010-07-08 18:53:58

回答

3

C99說,在7.19.5.3(fopen),第6款:

當一個文件被打開與更新模式( '+'作爲參數值的上述列表中的第二個或第三個字符),可以在關聯的流上執行輸入和輸出。然而,輸出不應直接跟隨輸入,如果沒有對[...]功能的干預調用,輸入不應該直接跟隨輸出,除非輸入操作遇到端點限制,的文件。

恭喜您在實踐中發現這個角落案例。庫的執行是完全正確的,因爲你違反了上面引用的應爲

順便說一下,從stderr中讀取並不罕見。當stdinstdout被重定向並且沒有終端可用時這很有用。儘管C99並不保證它是可讀的,但我記得在實際上已經完成的POSIX類系統上的一些情況。

+0

我不明白這是如何解決這個問題的。 – 2010-07-08 19:21:03

+0

它回答99%的問題。從理論上講,最後的「除非」條款可能意味着失敗的閱讀不計算在內,但我不認爲有人想到這種情況,因此它是未定義的。 – Amnon 2010-07-08 19:38:40

+0

@Amnon它說「當文件以更新模式打開時」 - 什麼讓你認爲stderr在該模式下打開?你不能在stderr上調用定位功能。 – 2010-07-08 19:43:28