getchar返回int类型
/* copy input to output; 2nd version */
main()
{
int c;
c = getchar();
while(c != EOF){
putchar(c);
c = getchar();
}
}
直觉告诉我getchar返回值应该是char类型的,这个地方为什么不能用char类型来存储getchar()的返回值呢?
其实文中解释的很清楚,可当时没有看明白:
在键盘或者屏幕上的字符都是用char类型存储的,当然也可以用int类型来存储。这个地方使用int来存储字符有一个微妙但很重要的原因:为了把有效数据和输入的结束(EOF)区分开来。getchar()在没有更多输入数据时返回一个特殊值,这个值不会跟任何实际的字符混淆。这个值称为 EOF(end of file,文件结束)。我们必须把c变量声明成一个大到足够存储任何getchar()返回的值的类型。我们不能用char类型,因为c必须大到足够容纳任意可能的char还有EOF。因此我们使用int类型。
如果你看到这里就明白了,或者早就知道原因,那可以不用接着看了。下面是我理解这个原因的思路。
1. getchar的函数声明
虽然看着getchar(),直觉告诉我这应该返回char类型吧,但还是让我们看看C语言中 getchar() 的函数声明:
嗯?返回值是int?(不靠谱的直觉啊)在Linux下输入命令:man getchar(),结果更加详细:
fgetc, fgets, getc, getchar, gets, ungetc - input of characters and strings
[…]
DESCRIPTION
fgetc() reads the next character from stream and returns it as an unsigned char cast to an int, or EOF on
end of file or error.
这样我们就明白了,getchar()从标准输入(stdin)流中读取一个字符,把它当作一个unsigned char,然后强制转化成int类型来做为返回值,如果遇到文件末尾或者错误,返回EOF。
2. EOF是什么
用google搜索时,首先看到了这样的一个帖子: EOF的定义和如何有效的使用它:
EOF不是:
- 一个char类型 (a char)
- 不是一个在文件末尾出现的值 (a value that exists at the end of a file)
- 不是一个可能在文件中间出现的值(a value that could exist in the middle of a file)
C99标准规定(见 7.19.1 Introduction):
which expands to an integer constant expression, with type int and a negative value, that
is returned by several functions to indicate end-of-file,that is, no more input from a
stream;
好,我们明白了 EOF 是一个宏,展开后为一个整数常量表达式(integer constant expression),是int类型(C语言中整数常量是int类型的),而且值是负值。一些函数用它作为返回值,表示流中没有更多的输入。
让我们去定义它的头文件<stdio.h>中去看看:
那么 EOF 在计算机中十六进制表示形式是 0xFFFFFFFF(有符号数在计算机中是一般用补码(two’s-complement)表示)。通过getchar函数的定义,我们知道getchar() 从标准输入(stdin)流中读取一个unsigned char类型的字符0xXX,然后强制转化成int 类型 0x000000XX(对无符号数,进行零扩展),此时这个值是大于等于零的。
所以,EOF(0xFFFFFFFF)不可能出现在文件中间(文本文件中),它与字符(character)是截然不同的值。
3.使用char类型存储getchar()这类函数的返回值
main()
{
char c;
c = getchar();
while(c != EOF){
putchar(c);
c = getchar();
}
}
上述这段代码中,c = getchar(); 会将getchar()的返回值int强制转化为char类型,就将32位的int截断为8位的char。之后的 c != EOF,又会将c强制转化为int类型,就将8位的char类型进行扩展,扩展为32位int类型。在扩展时,如果char类型为无符号数,进行零扩展,如果char类型为有符号数,进行符号扩展。下面的两个表分别展示了上面的这两个转换过程。为了制表方便,假设int是16位。
| int到char转化(截断) | | char到int转化(扩展) |
——————————— ———————————————-
| 十进制 | int | char | | char |unsigned char=>int| signed char=>int|
|———|————-|——-| |——-|——————|—————–|
| 2 |00 00 00 02 | 02 | | 02 | 00 00 00 02 |00 00 00 02 |
| 1 |00 00 00 01 | 01 | | 01 | 00 00 00 01 |00 00 00 01 |
| 0 |00 00 00 00 | 00 | | 00 | 00 00 00 00 |00 00 00 00 |
| EOF(-1) |FF FF FF FF | FF | | FF | 00 00 00 FF |FF FF FF FF |
| -2 |FF FF FF FE | FE | | FE | 00 00 00 FE |FF FF FF FE |
——————————– ———————————————-
可见,如果char是无符号的,那么上面那段代码中,当getchar()返回EOF时,c!=EOF 条件仍然满足。此时程序不能正常终止。
大家能不能自己写代码验证一下C语言中从char到int的、int到char的强制类型转化呢?
PS:
MSVC中char类型默认是有符号的char类型,可以在编译时加入 /J 参数来把默认的char类型从signed char 改变到 unsigned char
gcc中,char类型默认也是有符号的,可以在编译时加入参数 -funsigned-char 或者 -fsigned-char 来指定char的符号类型。
总结:感觉此问题是函数编写这考虑问题不全面引起的,属于设计缺陷,单单为了兼容eof而使得整个函数返回值为int类型,在内存稀缺的情况下是不明智的。完全可以通过在ASCII码中位eof找到一个位置来避免这个问题,当然如果是出于历史原因比如ascii在前而函数的编写在后,或者ascii码已满,无法为eof留下位置,则是一种好的折中方式。当然,也有可能函数的编写这考虑的更远,为了兼容两个字节的unicode编码方式,也是可能的。不管怎么样,只需要留意getchar返回值是int类型即可.
转载:http://www.chawenti.com/articles/11000.html
转载于:https://www.cnblogs.com/3me-linux/p/4121465.html
getchar返回int类型相关推荐
- Java返回int型的空值_使用MyBatis查询int类型字段,返回NULL值时报异常的解决方法...
当配置mybatis返回int类型时 select id="getUserIdByName" parameterType="string" resultType ...
- c语言int超出范围字符串,Go返回int64类型字段超出javascript Number范围的解决方法...
Go返回int64类型字段超出javascript Number范围的解决方法 最近在项目中,一个go服务给前端提供了一个接口,返回json格式数据,其中Int64字段会超出javascript Nu ...
- mysql int和bigdecimal,mysql的 int 类型,刨析返回类型为BigDicemal 类型的奇怪现象
用的是Map,List>接收, sql语句中int类型的值做了聚合运算, 满足上述两个条件. java中去取value的值就会变成BigDecimal 类型 经过实测:mybatis 中的sql ...
- mal是什么类型对应的java类型是什么,【Java】mysql的 int 类型,刨析返回类型为BigDicemal 类型的奇怪现象...
用的是Map,List>接收, sql语句中int类型的值做了聚合运算, 满足上述两个条件. java中去取value的值就会变成BigDecimal 类型 经过实测:mybatis 中的sql ...
- println()函数输出int类型返回值错误的问题
out.println(); 在用这个语句输出其他类返回大的int类型的数据的时候,注意输出错误. 例如: out.println(class1.方法()): 导致错误: our.println(c ...
- “GetDocument”: 缺少返回类型;假定为返回“int”的成员函数
在编译时出现: 1>正在编译... 1>PreviewDlg.cpp 1>d:\zac\project\vs2008\projects\dipalgorithm\dipalgorit ...
- java 返回值判断_在Java中判断方法重载的条件除了参数外,还可以通过返回值类型判断。_学小易找答案...
[单选题]若int x;且有下面的程序片断,则输出结果是() . for (x=3; x<6; x++) { printf((x%2) ? "##%d" : "** ...
- python参数类型限定_python限定方法参数类型、返回值类型、变量类型等|python3教程|python入门|python教程...
https://www.xin3721.com/eschool/python.html typing模块的作用 自python3.5开始,PEP484为python引入了类型注解(type hints ...
- c语言字符串作为函数返回值的类型,返回字符串类型的函数怎么写?
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 描述 请判断一个数是不是水仙花数. 其中水仙花数定义各个位数立方和等于它本身的三位数. 输入 有多组测试数据,每组测试数据以包含一个整数n(100< ...
最新文章
- can t connect to mysql server on ‘localhost‘解决方法
- 卫星导航精密单点定位(PPP)技术
- 单点登录实现(spring session+redis完成session共享)
- php 两个数据的交集_请问下在PHP中,如何返回两个数组的多个交集
- P3466-[POI2008]KLO-Building blocks【Treap】
- 基于Asterisk的VoIP开发指南(2)——Asterisk AGI程序编写指南
- 基于JAVA+Servlet+JSP+MYSQL的在线汽车订票系统
- 启动计算机时页面配置出现问题,开机提示“由于启动计算机时出现了页面配置问题…”...
- fscapture设置中文_Fscapture是什么软件?有没有功能介绍?
- .NET在抹黑代码中输入JS提示语句(背景不会变白)
- [转载] python dict 查找原理
- HTML与JSP页面的区别
- 手把手教你搭建FastDFS集群(下)
- git如何添加远程主机_Git由浅入深之远端主机(git remote)
- 学术汇报(academic presentation)/PPT应该怎么做?
- IAR下载并创建Example工程
- molar mass
- 第50篇 Android Studio实现生命数字游戏(五)计算星座数
- 爬虫 403 增加header和代理ip也没用?有可能是cloudflare在搞事情
- 2019 杭电第九场1007 Rikka with Travels
热门文章
- Linux06-服务、守护进程和systemd
- 区块链隐私:交易还是计算?
- redux logic_Redux-Logic简介
- 使用Python和NLTK的自然语言处理(NLP)教程
- 数据库更行通知_哪个更好? 数据驱动还是数据通知?
- java 静态代码块 多线程,Java多线程编程笔记10:单例模式
- mysql回表_到底什么情况下mysql innodb会发生回表操作?
- 台式计算机刚换的显示屏怎么设置,台式机怎么样切换显示器
- linux中怎么退出执行过程,(进程)处理过程中的Linux:从执行到退出
- Python培训教程分享:“高效实用” 的Python工具库