EOF的定义与有效使用(Definition of EOF and how to use it effectively )
2011-03-22 15:29
513 查看
原文:http://faq.cprogramming.com/cgi-bin/smartfaq.cgi?answer=1048865140&id=1043284351&utm_source=newletter&utm_medium=email&utm_campaign=twentyeight-followup
by Hammer ,ljbsdu译
EOF的使用以及意义看起来给新手程序员带来了不少困惑,希望这个解释能够帮助你更好的理解它。在深入的解释EOF是什么之前,我先告诉你EOF不是什么。
EOF不是:
1、一个字符;
2、一个存在于文件结尾的值;
3、一个可以存在于文件中间的值;
那它究竟是什么呢?
EOF是一个定义为负值的int型的宏。它通常用来作为进行读操作的函数的返回值,标志读操作错误或者到达输入的结尾。因为变量提升规则(稍后详细讨论),你必须谨记使用int变量来保存这些(读)函数的返回值,即使函数的返回值看起来是char,例如getchar()或fgetc();
下面是一些你可能用到的代码例子:
char到int的提升
根据定义,int表示的值比char大,所以一个负值的int绝不可能容纳与char相同的值(??)。但是,当你比较一个int和char时,char类型将会提升成为int型,以此来解释(?)变量在所占位数上的差异。char提升后的值受到它的符号的影响,不幸的是一个char变量既可以是有符号的也可以是无符号的,这取决于编译器。
为了更好的理解,让我们看一下一些int和char的代表性的数字。
下面假设int为2个字节(你的编译器可能会更多),char只使用1个字节(这个与你的编译器是一致的)。除了第一列,下面的值都是用16进制表示的。
从“char to int promotion”表可以很明显的看出char的符号导致产生不同的int值。
那么这些对一个程序员来说意味着什么?
嗯,让我们看一个上面的代码的修改版,这次我们将错误的使用一个char变量来保存fgetc()函数的返回值;
现在我们假设我们正在读取的是文件中的一个值为0xff的byte。fgetc()将以int型返回该值,所以它看起来应该是这样0x00 0xff(同样
,我假设一个int为2个字节)。为了在char中存储该值,char就必须降级,所以字节值就变为0xff。
然后,字节c与int型的EOF比较。提升规则起作用了,c必须提升为int型。但是在例子代码中,c的符号并没有显式的声明,所以我们并不知道它是有符号还是无符号的,所以提升后的int值可能为0xff 0xff也可能为0x00 0xff。所以代码并不保证按照我们的要求运行。
下面是一段小的程序帮助展示这种提升。
另一个需要考虑的情况是当char是无符号时。这种情况下,对fgetc()函数的返回值的降级或者提升的过程将会对EOF的值产生破坏作用,并且将会使程序陷入死循环。让我们看一下整个过程:
-----在fgetc()在到达输入结尾时返回EOF(0xff 0xff),然后被降级为0cff,放到一个无符号char变量c中,无符号的char c提升为int,值由0xff变为0xff 0xff,EOF与c比较,即0xff 0xff 与0x00 0xff之间的比较。结果为false(因为值不同),这并不是所期望的。fgetc()又一次被调用,仍然返回EOF,死循环开始了!
下面的代码演示了这个问题。
by Hammer ,ljbsdu译
EOF的使用以及意义看起来给新手程序员带来了不少困惑,希望这个解释能够帮助你更好的理解它。在深入的解释EOF是什么之前,我先告诉你EOF不是什么。
EOF不是:
1、一个字符;
2、一个存在于文件结尾的值;
3、一个可以存在于文件中间的值;
那它究竟是什么呢?
EOF是一个定义为负值的int型的宏。它通常用来作为进行读操作的函数的返回值,标志读操作错误或者到达输入的结尾。因为变量提升规则(稍后详细讨论),你必须谨记使用int变量来保存这些(读)函数的返回值,即使函数的返回值看起来是char,例如getchar()或fgetc();
下面是一些你可能用到的代码例子:
int c; while ((c = fgetc(fp)) != EOF) { putchar (c); }
int ch; while ((ch = cin.get()) != EOF) { cout <<(char)ch; }
char到int的提升
根据定义,int表示的值比char大,所以一个负值的int绝不可能容纳与char相同的值(??)。但是,当你比较一个int和char时,char类型将会提升成为int型,以此来解释(?)变量在所占位数上的差异。char提升后的值受到它的符号的影响,不幸的是一个char变量既可以是有符号的也可以是无符号的,这取决于编译器。
为了更好的理解,让我们看一下一些int和char的代表性的数字。
下面假设int为2个字节(你的编译器可能会更多),char只使用1个字节(这个与你的编译器是一致的)。除了第一列,下面的值都是用16进制表示的。
----------------------------- ------------------------------ | 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 | ----------------------------- ------------------------------
从“char to int promotion”表可以很明显的看出char的符号导致产生不同的int值。
那么这些对一个程序员来说意味着什么?
嗯,让我们看一个上面的代码的修改版,这次我们将错误的使用一个char变量来保存fgetc()函数的返回值;
char c; while ((c = fgetc(fp)) != EOF) { putchar (c); }
现在我们假设我们正在读取的是文件中的一个值为0xff的byte。fgetc()将以int型返回该值,所以它看起来应该是这样0x00 0xff(同样
,我假设一个int为2个字节)。为了在char中存储该值,char就必须降级,所以字节值就变为0xff。
然后,字节c与int型的EOF比较。提升规则起作用了,c必须提升为int型。但是在例子代码中,c的符号并没有显式的声明,所以我们并不知道它是有符号还是无符号的,所以提升后的int值可能为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; } /* * Output Comparing ffff with ffff <--- Notice this has been promoted i == sc Comparing ffff with ff i != usc * */
另一个需要考虑的情况是当char是无符号时。这种情况下,对fgetc()函数的返回值的降级或者提升的过程将会对EOF的值产生破坏作用,并且将会使程序陷入死循环。让我们看一下整个过程:
-----在fgetc()在到达输入结尾时返回EOF(0xff 0xff),然后被降级为0cff,放到一个无符号char变量c中,无符号的char c提升为int,值由0xff变为0xff 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; }
相关文章推荐
- (Page 1 of 3 )A walking tour of JavaBeans What JavaBeans is, how it works, and why you want to use it
- (Page 2 of 3 )A walking tour of JavaBeans 2 :What JavaBeans is, how it works, and why you want to use it
- (Page 3 of 3 )A walking tour of JavaBeans What JavaBeans is, how it works, and why you want to use it
- 为何以及如何使用Netlink Socket ( Why and How to Use Netlink Socket)
- (zhuan) Attention in Neural Networks and How to Use It
- how to save a c++ object in java object and use it
- How to create a DLL library in C and then use it with C#
- iOS开发UI-Quartz2D what about Quartz2D ?and how to use it ?
- jooq使用自定义策略生成代码(How to use a custom strategy with the jOOQ code-generator and Maven?)
- Introduction to COM - What It Is and How to Use It.
- 为何以及如何使用Netlink Socket ( Why and How to Use Netlink Socket)
- [Mootools] Simple tutorial of how to use domReady, DOM operation and Ajax in Mootools
- WHAT IS ISO? A CAMERA’S SENSITIVITY TO LIGHT EXPLAINED, AND HOW TO USE IT
- the command 'vim' and how to use it
- MySpace Unraveled: What it is and how to use it safely
- Responsive Web Design: What It Is and How To Use It
- How to build & install GLFW 3 and use it in a Linux project
- 安装ipython,使用scrapy shell来验证xpath选择的结果 | How to install iPython and how does it work with Scrapy Shell
- How to use outline levels to create a table of contents (TOC) in Word 2003 and in Word 2002
- 为何以及如何使用Netlink Socket ( Why and How to Use Netlink Socket)