2011-01-20 35 views
4

我在C練習中使用getc();,回顧程序後,我發現一些奇怪的東西。我認爲在命令行參數上給出的文件至少包含一個字節。 (它在連續兩次調用getc();時沒有檢查EOF,在一個空文件上嘗試它後仍能正常工作我的問題是:getc();對已耗盡的文件指針的行爲(EOF已達到並且未被重新綁定)未定義還是會一直繼續返回EOF?getc()在返回EOF後定義了嗎?

我想我可能會擴大這個問題在C++ STL所有的I/O功能,請在你的答案太清楚這一點。

這裏是程序的代碼,該程序應該從所有註釋中剝離一個C/C++源文件(並且它可以很好地工作)

#include <stdio.h> 

int main(int argc, char *argv[]) { 
    int state = 0; // state: 0 = normal, 1 = in string, 2 = in comment, 3 = in block comment 
    int ignchar = 0; // number of characters to ignore 
    int cur, next; // current character and next one 
    FILE *fp; // input file 

    if (argc == 1) { 
     fprintf(stderr, "Usage: %s file.c\n", argv[0]); 
     return 1; 
    } 

    if ((fp = fopen(argv[1], "r")) == NULL) { 
     fprintf(stderr, "Error opening file.\n"); 
     return 2; 
    } 

    cur = getc(fp); // initialise cur, assumes that the file contains at least one byte 
    while ((next = getc(fp)) != EOF) { 
     switch (next) { 
      case '/': 
       if (!state && cur == '/') { 
        state = 2; // start of comment 
        ignchar = 2; // don't print this nor next char (//) 
       } else if (state == 3 && cur == '*') { 
        state = 0; // end of block comment 
        ignchar = 2; // don't print this nor next char (*/) 
       } 
       break; 
      case '*': 
       if (!state && cur == '/') { 
        state = 3; // start of block comment 
        ignchar = 2; // don't print this nor next char (/*) 
       } 
       break; 
      case '\n': 
       if (state == 2) { 
        state = 0; 
        ignchar = 1; // don't print the current char (cur is still in comment) 
       } 
       break; 
      case '"': 
       if (state == 0) { 
        state = 1; 
       } else if (state == 1) { 
        state = 0; 
       } 
     } 

     if (state <= 1 && !ignchar) putchar(cur); 
     if (ignchar) ignchar--; 
     cur = next; 
    } 

    return 0; 
} 
+0

對不起,但只是爲了清楚起見,這是C還是C++?它看起來像C,但我寧願檢查,而不僅僅是編輯。 – 2011-01-20 23:32:45

+0

這是C,我認爲它也可以應用於C++,但我會刪除標籤以減少歧義。 – orlp

回答

6

Stdio文件保留第一次達到文件結束時設置的「eof」標誌,並且只能通過調用clearerr或執行成功的fseekrewind進行重置。因此,一旦getc返回EOF一次,即使新數據變得可用,它也將保持返回EOF,除非您使用上述方法之一來清除eof標誌。

一些不符合規定的實現可能會立即提供新的數據。這種行爲是有害的,可能會破壞符合標準的應用程序。

+0

請注意,傳統的Unix系統具有破壞的行爲,並且一些現代系統可能會將其複製爲「兼容性」。所以我會避免依賴任何行爲。 –

1

如果流上的EOF標誌設置,getc應該返回EOF(如果你一直在打getc,應該回頭率EOF)。

+0

因此,在流的'EOF'標誌設置爲'getc();'應該總是返回'EOF',即使你稱它爲一千次。和'fseek();'如果你倒回去掉國旗,我想? – orlp

1

從邏輯上講,我認爲它應該永遠返回EOF

getc根據fgetc定義。

的GETC()函數應當相當於龜etc(),所不同的是,如果它 被實現爲一個宏它可以評估流不止一次,所以 參數絕不應具有副作用的表達。

fgetc文檔說:

如果用於流的結束文件指示符被設置,或者如果流 是在結束文件,端OF-該流的文件指示符應設置爲 ,並且fgetc()應返回EOF。

並且「在文件結束時」可以通過調用feof來確定。

feof文檔說:當且僅當結束文件的 指示符被設置爲流

的FEOF()函數將返回非零。

所以除非發生什麼事情來清除文件結束指示符,否則它應該永遠繼續返回EOF

+1

是否有任何理由使用'getc();'over'fgetc();'然後'getc();'可能會在宏中實現,因此可能進行多次評估。 (除了保存一個字符)。 – orlp

+2

在大多數歷史系統中,'getc'是一個宏,它嵌入FILE內部,只在緩衝區爲空時才進行函數調用。現代標準要求'getc'在多個線程從同一個'FILE'讀取時是線程安全的,所以宏定義已經過時,但原則上現代實現仍然可以使用宏,如果它能夠有效地檢測到只有一個線程正在運行。 –

相關問題