[英]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
在成功讀取時返回“轉換為int
的unsigned char
”。 由於unsigned char
不能具有負值,因此可以將EOF
的值與從流中讀取的任何內容區分開來。 *
*請參見下文,了解未能解決的漏洞案例。
相關標准文本(來自C99):
§5.2.4.2.1整數類型的大小<limits.h>
:
[]實現定義的值的大小(絕對值)應等於或大於所示的值,並帶有相同的符號。
[...]
int
類型對象的最小值
INT_MIN
-32767int
類型對象的最大值
INT_MAX
+32767
§7.19.1 <stdio.h>
- 簡介
EOF
...擴展為整數常量表達式,類型為int
和負值,由多個函數返回以指示文件結束,即不再從流中輸入
§7.19.7.1將fgets
功能
如果輸入流中的結束文件指針指向的
stream
沒有設置和下一個字符存在,則fgetc
函數獲取字符作為unsigned char
轉換為int
和推進相關聯的文件中的位置指示器的流(如果定義)
如果UCHAR_MAX
≤ INT_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 char
和int
具有相同數量的唯一值時。 這種情況發生在罕見的平台上,包括char
, signed char
, unsigned char
, short
, unsigned short
, int
, unsigned
所有這些都使用相同的位寬和范圍寬度。
請注意, 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.