为什么getch()返回之前按任何键?

int main(int argc, char *argv[], char *env[]) { printf("Press any key to exit.\n"); getch(); return 0; } 

根据手册页,

getch应该等到任何键被按下

…但实际上它在按任何键之前直接返回。 (返回的值是-1 )。

为什么?


更新

我在Linux上。 我如何实现Press any key to exit. ,如果不使用getch()

按回车后, getchar()将只返回,这不是我想要的。

Solutions Collecting From Web of "为什么getch()返回之前按任何键?"

在Linux上, getch()可能是curses函数,与具有相同名称的Windows特定函数完全不同。 cursesncurses )对于你想做的事情可能是过度的。

最简单的方法是等到用户按下Enter ,你可以这样做:

 int c; printf("Press <enter> to quit: "); fflush(stdout); while ((c = getchar()) != '\n' && c != EOF) { /* nothing */ } 

如果你真的希望用户能够按任何键,而不只是输入 ,你可以做这样的事情:

 system("stty cbreak -echo"); getchar(); system("stty cooked echo"); 

第二个stty旨在将tty恢复到合理的设置(它应该真正恢复到原来的状态,但是保存和恢复状态要复杂一点)。 有可能更干净的方法来做到这一点(使用stty程序本身使用的任何库函数)。

编辑:阅读单个字符而不等待输入是一个经常被问到的问题。 事实上,这是comp.lang.c FAQ中的问题19.1。

编辑2:最近我还没有和诅咒做过多的工作,但我只是做了一些玩弄。 看来getch()将不起作用,除非你首先调用initscr()initscr()清除屏幕。 curses旨在用于需要完全控制显示的文本编辑器等应用程序。 可能有一种方法可以使用getch()而不需要控制屏幕,但是我还没有找到它。

system("stty ...") kludge实际上可能是最好的方法。

EDIT3:在另一个答案的termios解决方案可能是最好的( system("stty ...")更简单,但调用外部程序感觉像矫枉过正。

至于OP的评论:“我不敢相信Press any key to exit. ,在c里做这么麻烦”,是的,这看起来很奇怪,但进一步的想法是有道理的。

看看典型的Unix或Linux系统上安装的程序。 我想你会发现很少有人需要这种输入(等待一个按键)。

很多程序可以使用从文件或stdin读取的命令行参数和数据。 用户输入的任何内容都是输入数据,而不是命令或对提示的响应。

有些程序要求确认某些操作(像apt-getcpan这样的安装程序经常这样做) – 但是他们通常会读取一行输入并检查第一个字符。 或者,对于一些激烈的行动,他们可能会要求你输入整个单词“是”,然后输入 (你不想重新格式化你的硬盘驱动器,因为你不小心按了一个键)。

当然很多程序(文本编辑器,文件查看器)读取单个字符的非回显输入,但是这样的程序往往是基于curses的; 他们控制整个终端窗口。

最后,一些程序有GUI界面(网页浏览器等)。 他们可能甚至没有从标准输入读取。

大多数生产Unix程序不使用或需要Press any key to exit提示。 他们只是默默地做自己的工作,然后终止,这样你就可以做下一件事了。 主要需要相对基础的课程,比如家庭作业。 并不是说家庭作业有什么问题,但整个系统的主要目的不是为了支持这种使用。

这是一个简单的例子

 #include <curses.h> int main(){ initscr(); cbreak(); noecho(); printw("Press any key to continue."); refresh(); getch(); endwin(); return 0; } 

但似乎没有任何方法来使用ncurses而不清除屏幕。 矫枉过正的污点,也许?!

编辑

这是我工作的另一种方式。 这不使用诅咒,也不清除屏幕。

 #include <stdio.h> #include <termios.h> #include <unistd.h> int main() { struct termios old,new; tcgetattr(fileno(stdin),&old); tcgetattr(fileno(stdin),&new); cfmakeraw(&new); tcsetattr(fileno(stdin),TCSANOW,&new); fputs("Press any key to continue.",stdout); fflush(NULL); fgetc(stdin); tcsetattr(fileno(stdin),TCSANOW,&old); return 0; } 

手册页说cfmakeraw()可能不是完全可移植的。 但是这只是一个简单的标志:

 Raw mode cfmakeraw() sets the terminal to something like the "raw" mode of the old Version 7 terminal driver: input is available character by character, echoing is disabled, and all special pro- cessing of terminal input and output characters is disabled. The terminal attributes are set as follows: termios_p->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); termios_p->c_oflag &= ~OPOST; termios_p->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); termios_p->c_cflag &= ~(CSIZE | PARENB); termios_p->c_cflag |= CS8;