您的位置:首页 > 编程语言 > C语言/C++

C语言中 EOF的定义以及如何有效地运用

2010-05-29 10:59 99 查看
EOF的定义和运用看来给一些入门编程者带来了许多困惑,我希望以下的解释能有助于你更好地理解它。 在我向你详细地讲述EOF是什么之前,

我要首先告诉你它不是什么。

EOF不是:

(1) 一个字符

(2) 存在于文件结尾的一个数

(3) 存在于文件中数

EOF
是:

EOF是一个定义为负值的宏。通常,一个函数在读取过程中出错或到了输入结尾时就会返回EOF。

由于类型提升规则
(variable promotion rules,下文中讲述),用int型变量来存取一些函数返回值十分必要,即使这些函数返回一个

字符,如 getchar()和fgetc().

以下是一些你可能会用到的示例代码:

int c;

while ((c = fgetc(fp)) != EOF)

{

putchar (c);

}

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

int
ch;

while ((ch = cin.get()) != EOF)

{

cout <<(char)ch;

}

字符型转换为整型

在定义上,一个int型变量的范围比一个char型的大,因此,一个负的int型数不能表示一个字符。但是,当你比较
一个int型数和一个

char型数时,由于这两个变量在内存尺寸上的不同,这个char型数将会被提升为一个int型数。被提升后的char型变量的值受符号位的影响,


糕的是,一个char型变量在缺省情况下既可以是有符号的也可以是无符号的,这些取决于所用的编译器。

为了更好地理解,让我们看几个int
型和char型的实例。假定int型变量为二个字节,char型仅有一个字节。除了第一栏,所有数值都用十六进

值表示。

-----------------------------
------------------------------

| char and int comparison |
| char to int promotion |

-----------------------------
------------------------------

| Decimal | int | char |
| char | unsigned | signed |

|---------|---------|-------|
|-------|----------|---------|

| 2 | 00 02 | 02 |
| 02 | 00 02 | 00 02 |

| 1 | 00 01 | 01 |
| 01 | 00 01 | 00 01 |

| 0 | 00 00 | 00 |
| 00 | 00 00 | 00 00 |

| -1 | FF FF | FF |
| FF | 00 FF | FF FF |

| -2 | FF FE | FE |
| FE | 00 FE | FF FE |

-----------------------------
------------------------------

The "char to int promotion" table makes it clear that the sign of a
char produces a very different number in the int.

So what does all
this mean to me as a programmer?

上面的表格很清晰地显示:有符号字符型在转换后变成了一个大不相同的整型
数。

让我们修改一下前面的代码,用字符型变量来存储fgetc()的返回值。

char c;

while ((c =
fgetc(fp)) != EOF)

{

putchar (c);

}

现在我们假定从文件中读取了一个字节,该字节的
值为0xff. fgetc()在一个整型变量中返回了这个值,它看起来是:0x00 0xff(再次假定整

型变量为二个字节)。为了将这个结果存放在一个字符型变量中,它必须被降级(demote),因此字符型的值变为0xff.接下来,字符型c与整型

的EOF比较。提升规则开始起作用了,c必须被提升为整型。但是,在代码中,c的符号并未显式地声明,所以我们不知道它是有符号的还是无符

号的,整型的数值可能为0xff 0xff或者0x00 0xff.

因此,不能保证这段代码会按照这们设想的方式执行。

下面是一小
段展示这些转换的代码:

#include <stdio.h>

int main(void)

{

int
i = -1;

signed char sc = 0xff;

unsigned char usc = 0xff;

printf ("Comparing %x with %x/n", i, sc);

if (i == sc)
puts("i == sc");

else puts("i != sc");

putchar
('/n');

printf ("Comparing %x with %x/n", i, usc);

if (i ==
usc) puts("i == usc");

else puts("i != usc");

return 0;

}

/*

* 输出

比较ffff和ffff <--- 注意这些值已经提升过了

i ==
sc

比较ffff和ff

i != usc

*

*/

在有些情况下程序可能会陷入无限循环中。

-由于到达输入末尾(即到了文件结尾),fgetc()返回EOF(0xff 0xff)

-返回值被降级为0xff,以便能存入无符号字符
型变量c中

-无符号字符型变量c被提升为整型,值由0xff变为0x00 0xff

-EOF与c进行比较,即0xff
0xff与0x00 0xff间的比较

-结果为FALSE(两个值不同),结果出乎意料

-fgetc()再次被调用,但仍然返回EOF.
死循环开始

以下的代码可以证明这个问题。

#include <stdio.h>

int main(void)

{

FILE *fp;

unsigned char c;

if ((fp = fopen("myfile.txt", "rb")) == NULL)

{

perror
("myfile.txt");

return 0;

}

while ((c =
fgetc(fp)) != EOF)

{

putchar (c);

}

fclose(fp);

return 0;

}

原文:

Definition of EOF and how to use it effectively

The use and meaning of
EOF
seems to
cause a lot of confusion with

some new
coders, hopefully this explanation will help you understand better.
Before I go into too much detail about what
EOF
is, I'll
tell you what it isn't.

EOF
is NOT:

·

A char

·

A value
that exists at the end of a file

·

A value
that could exist in the middle of a file

And now to what it actually is.

EOF
is a macro defined as an int
with a negative value. It is normally returned by functions that perform
read operations to denote either an error or end of input. Due to
variable promotion rules (discussed in detail later), it is important to
ensure you use an int to store the return code from these functions,
even if the function appears to be returning a char, such as
getchar()
or
fgetc()
.

Here are some code examples that you might use:

int
c;

while
((c = fgetc(fp)) != EOF)

{

putchar (c);

}

int
ch;

while
((ch = cin.get()) != EOF)

{

cout <<(
char
)ch;

}

char to int Promotion

By definition an int is larger than a
char, therefore a negative valued int can never hold the same value as a
char. However, when you compare an int with a char, the char will get
promoted to an int to account for the difference in size of the
variables. The value of a promoted char is affected by its sign, and
unfortunately, a char can be either signed or unsigned by default, this
is compiler dependant.

To understand this better, let's look
at the representation of a few numbers in both ints and chars.

The following assumes 2 byte ints
(your compiler might use a larger amount). A char uses only 1 byte (this
will be the same amount on your compiler). With the exception of the
first column, the values are shown in hexadecimal.

-----------------------------
------------------------------

|
char and int comparison
|
|
char to int
promotion
|

-----------------------------
------------------------------

| Decimal |
int
|
char
|
|
char | unsigned
| signed
|

|---------|---------|-------|
|-------|----------|---------|

|
2
|
00
02
|
02
|
|
02
|
00 02
|
00
02
|

|
1
|
00
01
|
01
|
|
01
|
00 01
|
00
01
|

|
0
|
00
00
|
00
|
|
00
|
00 00
|
00
00
|

| -1
|
FF FF
|
FF
|
|
FF
|
00
FF
|
FF FF

|

| -2
|
FF FE
|
FE
|
|
FE
|
00
FE
|
FF FE

|

-----------------------------
------------------------------

The "char to int promotion" table
makes it clear that the sign of a char produces a very different number
in the int.

So what does all this mean to me as a
programmer?


Well, let's have a look at a revised
version of the code shown above, this time incorrectly using a char
variable to store the return code from
fgetc()
.

char
c;

while
((c = fgetc(fp)) != EOF)

{

putchar (c);

}

Now let's assume that within the
file we are reading from is a byte with value 0xff.
fgetc()
returns
this value within an int, so it looks like this: 0x00 0xff (again, I'm
assuming 2 byte ints). To store this value in a char, it must be
demoted, and the char value becomes 0xff.

Next, the char c is compared with the
int EOF. Promotion rules apply, and c must be promoted to an int.
However, in the sample code, the sign of c isn't explicitly declared, so
we don't know if it's signed or unsigned, so the int value could become
either 0xff 0xff or 0x00 0xff. Therefore, the code is is not guaranteed
to work in the way we require.

The following is a short program to
help show the promotion:

#include
<stdio.h>

int
main(
void
)

{

int
i = -
1
;

signed

char
sc = 0xff;

unsigned

char
usc =
0xff;

printf (
"Comparing %x with
%x/n"
, i, sc);

if
(i ==
sc)
puts(
"i == sc"
);

else

puts(
"i != sc"
);

putchar (
'/n'
);

printf (
"Comparing %x with
%x/n"
, i, usc);

if
(i ==
usc)
puts(
"i == usc"
);

else

puts(
"i != usc"
);

return

0
;

}

/*

*
Output

Comparing
ffff with ffff
<--- Notice this has been
promoted

i
== sc

Comparing
ffff with ff

i
!= usc

*

*/

Another scenario to consider is
where the char is unsigned. In this case, the process of demoting and
promoting the returned value from
fgetc()
will have
the affect of corrupting the
EOF
value, and the program will
get stuck in a infinite loop. Let's follow that process through:

- EOF (0xff
0xff) is returned by fgetc() due to end of input

- Value
demoted to 0xff to be stored in unsigned char c

- unsigned
char c promoted to an int, value goes from 0xff to 0x00 0xff

- EOF is
compared with c, meaning comparison is between 0xff 0xff and 0x00 0xff.

- The result
is FALSE (the values are different), which is undesirable.

- fgetc() is
called again, and still returns EOF.
The endless
loop begins.

The following code demonstrates
this problem.

#include
<stdio.h>

int
main(
void
)

{

FILE *fp;

unsigned

char
c;

if
((fp =
fopen(
"myfile.txt"
,
"rb"
)) == NULL)

{

perror (
"myfile.txt"
);

return

0
;

}

while
((c =
fgetc(fp)) != EOF)

{

putchar (c);

}

fclose(fp);

return

0
;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: