标题:关于 getch()的问题
只看楼主
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
得分:0 
getch()是专用于控制台I/O的函数。控制台的英文是Console,故凡是与控制台具体环境有关的底层I/O函数,都被封装在conio头中(头包括.h和.lib/.dll两部分,不要以为只有.h就可以,.h是头文件,相当于书的目录,,lib或.dll才是写好的实现代码,编译好后供执行的,才是书的内容,价值存在于实现中,不在头文件中。只要不是开源的,你就看不到函数的实现代码,只能猜它怎么做出来的),conio就是console-I/O的缩写。

控制台I/O,是较之于getchar()文件流模式更底层的界面,它透过操作系统直接与硬件打交道。操作系统由硬件的驱动程序驱动,向主要I/O设备输入和输出,主要I/O设备一般是键盘和屏幕。当我们按动键盘时,驱动程序把按键信息输出给操作系统,操作系统根据自己的定义,把这些按键翻译为相应的统一键盘扫描码(这是在该操作系统下所有应用程序的共同协议,只要看一下世界上有多少种布局和键位各不相同的键盘就知道操作系统为什么要统一键盘扫描码了)。这种底层按键信息,是立刻接收到的。比较一下getchar()行为,就能更深刻地理解getch()的不同:前者在我们按键时,只要不按下回车键,程序的执行指针就一直被滞留在getchar()函数处,后面的代码是无法执行的,所以我们在用这个函数的时候,会发现尽管只用了一个getchar(),但却可以按下无限的按键,直到按下回车键,那个getchar()才返回刚才一系列按键的第一个键,然后后面一大堆键码就残存在键盘缓冲区中,被下一句getchar()函数接收(这就是我们用getchar()/scanf()等函数时经常要清空输入缓冲区的原因,否则会干扰程序数据的正确接收);另外一个毛病,这种无限的键入,很容易把屏幕的显示信息弄乱,打破你精心排版的画面,就这一点来说,getchar()函数根本不能实用。与此相对,getch()函数是立刻返回的,只要按下一个键(包括组合键,比如Ctrl+C或F1、PagUp/PgDown这类键),getchar()函数就返回了,让你的程序代码有机会马上检查这个按键是否符合要求,作出舍弃或储存的决定,绝不需要像getchar()那样在按下回车键后才知道前面按过了什么(做游戏程序时,getchar()是死翘翘了),比如,我要输入一个数字,用getch()函数,就可以检查用户每一个按键是不是阿拉伯数字或正负号、小数点这类键,如果不是,只要不储存这个按键(也不会回显,光标不会移动,像根本没按过一样),继续接收下一个按键就是了,它也可以让程序员设定是用回车结束输入还是用别的什么键结束,也可以不让用户输入两次小数点,可以边输入边排版数据,可以把输入的字符变成星号或别的特殊符号隐藏真正的输入内容,这些都是getchar()函数无法做到的。

每个平台,都有自己的一套键盘硬件处理法则。DOS/Windows把回车键(扫描码0x0d)翻译到文本中时,会自动添加一个字符0x0a,凑成双字节的回车换行符,对应C转义字符中的'\n',而若是在二进制文件中,它不会做这种翻译,是原封不动地传输0x0d,所以文件在存储为"t"或"b"模式时,长度是不一样的,原因就在这里。但在Linux这类平台中,它的‘\n'转义字符就只是0x0a('\r'才对应0x0d)。当我们说平台移植的时候,特别是文件数据上的处理,就必须要考虑这个问题了,用流输入输出,'\n'转义字符由系统和编译器配合解释,两者的表现一致,具体隐藏的细节不同(这也是不同平台的C标准库实现代码其实是不同的原因),但若直接对硬件编程,就只能自己区别处理,这就是getchar()可移植、getch()不可移植的原因,归根结底是后者直接对硬件编程造成的。getch()的响应速度,比getchar()快得多,因为前者直接读写硬件(其实是更底层的API通讯,与DOS时代的DOS中断相当,而那个时代还有更底层的BIOS中断可用,速度更快),后者却是高级封装函数。

关于基础知识,就先说这么多,楼主如果真有兴趣,可以接着告诉你getch()类函数的一些使用细节,比如键盘扫描码清单。

[ 本帖最后由 TonyDeng 于 2014-6-17 00:05 编辑 ]

授人以渔,不授人以鱼。
2014-06-16 23:45
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
得分:0 
在这里顺便谈谈EOF的问题。实际上,EOF是不能在键盘中输入的,getchar()返回EOF,取决于操作系统认什么标志为流数据出错,不同的系统有不同的约定。在DOS/Windows中,把按键Ctrl+Z(亦即F6)的扫描码认作为控制台Input出错,在这个平台上的getchar()函数实现代码,在遇到这个键码时,会舍弃这个键,然后直接设定函数的返回值为EOF,也就是说,这个返回值其实与你按了什么键是没有关系的(换言之,就是在我们用getch()编制自己的scanf()函数时,可以用任何自定义的按键作为结束符并返回EOF)。在Linux上,是另外一套按键。两个平台上同一个getchar()函数的实现代码,是不同的,或者是它有一个很复杂的判断树,去判别当前的环境来决定如何返回EOF——实际上是前者,因为标准库函数不可能穷尽世界上所有可能的系统,除了在不同的平台上有不同的库实现外,不可能有更有效的方法。

C程序的可移植性其实没有你想象中和宣传中那么好,亦即你完全按照标准写,在不同平台上也要把同一套源代码重新编译一次,以便用上该平台上库函数的实际可执行代码,不是你在Windows上编译好C程序可以拿到Linux上运行的——基于虚拟机的程序可以!

授人以渔,不授人以鱼。
2014-06-17 00:35



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-432920-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.612706 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved