簡體   English   中英

使用fgetc時,是否可以將EOF與正常的字節值混淆?

[英]Is it possible to confuse EOF with a normal byte value when using fgetc?

我們經常使用這樣的fgetc

int c;
while ((c = fgetc(file)) != EOF)
{
    // do stuff
}

從理論上講,如果文件中的某個字節的值為EOF ,則此代碼有問題 - 它會提前中斷循環並且無法處理整個文件。 這種情況可能嗎?

據我所知, fgetc內部將從文件讀取的字節轉換為unsigned char ,然后轉換為int ,並返回它。 如果int的范圍大於unsigned char的范圍,這將起作用。

如果不是(可能那么sizeof(int)=1 )會發生什么?

  • fgetc有時會從文件中讀取等於EOF的合法數據嗎?
  • 它會改變從文件中讀取的數據以避免單值EOF嗎?
  • fgetc會是一個未實現的功能嗎?
  • EOF會不會是另一種類型,比如long

我可以通過額外的檢查使我的代碼變得簡單:

int c;
for (;;)
{
    c = fgetc(file);
    if (feof(file))
        break;
    // do stuff
}

如果我想要最大的便攜性,這是必要的嗎?

C規范說int必須至少能夠保存-32767到32767之間的值。 任何具有較小int平台都是非標准的。

C規范還說EOF是負int常量,並且fgetc在成功讀取時返回“轉換為intunsigned char ”。 由於unsigned char不能具有負值,因此可以將EOF的值與從流中讀取的任何內容區分開來。 *

*請參見下文,了解未能解決的漏洞案例。


相關標准文本(來自C99):

  • §5.2.4.2.1整數類型的大小<limits.h>

    []實現定義的值的大小(絕對值)應等於或大於所示的值,並帶有相同的符號。

    [...]

    • int類型對象的最小值

      INT_MIN -32767

    • int類型對象的最大值

      INT_MAX +32767

  • §7.19.1 <stdio.h> - 簡介

    EOF ...擴展為整數常量表達式,類型為int和負值,由多個函數返回以指示文件結束,即不再從流中輸入

  • §7.19.7.1將fgets功能

    如果輸入流中的結束文件指針指向的stream沒有設置和下一個字符存在,則fgetc函數獲取字符作為unsigned char轉換為int和推進相關聯的文件中的位置指示器的流(如果定義)

如果UCHAR_MAXINT_MAX ,是沒有問題的:所有的unsigned char值將被轉換成非負整數,所以他們會從不同的EOF。

現在, 一個有趣的某種漏洞的位置:如果系統有UCHAR_MAX > INT_MAX ,則系統被法律允許超過轉換值大於INT_MAX負整數(每§6.3.1.3,值轉換為有符號的結果無法表示該值的類型是實現定義的 ),使得從流中讀取的字符可以轉換為EOF。

CHAR_BIT > 8系統確實存在(例如TI C4x DSP,它顯然使用32位字節),雖然我不確定它們是否在EOF和流功能方面有所破壞。

是的, c = fgetc(file); if (feof(file)) c = fgetc(file); if (feof(file))確實可以實現最大的可移植性。 它通常起作用,並且當unsigned charint具有相同數量的唯一值時。 這種情況發生在罕見的平台上,包括charsigned charunsigned charshortunsigned shortintunsigned所有這些都使用相同的位寬和范圍寬度。

請注意, feof(file))不足。 代碼還應檢查ferror(file)

int c;
for (;;)
{
    c = fgetc(file);
    if (c == EOF) {
      if (feof(file)) break;
      if (ferror(file)) break;
    }
    // do stuff
}

注意:在最常見的情況下,chux的答案是正確的。 我將這個答案留下來,因為我相信評論中的答案和討論對於理解chux的方法是必要的(罕見)情況是有價值的。

EOF保證具有負值(C99 7.19.1),如您所述,fgetc在轉換為int之前將其輸入讀取為unsigned char。 所以那些自己保證不能從文件中讀取EOF。

至於你的具體問題:

  • fgetc無法讀取等於EOF的合法數據。 在文件中,沒有簽名或未簽名的東西; 它只是位序列。 它是C,以不同的方式解釋1000 1111,具體取決於它是被視為有符號還是無符號。 fgetc需要將其視為無符號,因此無法返回負數(EOF除外)。

    附錄:它無法讀取unsigned char部分的EOF,但是當它將unsigned char轉換為int時,如果int不能表示unsigned char的所有值,則行為是實現定義的(6.3。 1.3)。

  • fgetc是托管實現的標准所必需的,但允許獨立實現省略大多數標准庫函數(有些顯然是必需的,但我找不到列表。)

  • EOF不需要很長時間,因為fgetc需要能夠返回它並且fgetc返回一個int。

  • 就改變數據而言,它不能准確地改變 ,但由於fgetc被指定為從文件中讀取“字符”而不是字符,因此即使系統也可能一次讀取8位否則將CHAR_BIT定義為16(如果sizeof(int)== 1,則它可以具有的最小值,因為5.2.4.2需要INT_MIN <= -32767和INT_MAX> = 32767)。 在這種情況下,輸入字符將轉換為無符號字符 ,它始終具有高位0.然后它可以轉換為int而不會丟失精度。 (實際上,這不會出現,因為機器一般不具有16位字節)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM