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

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 ;

}

阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭