10
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()只会在按 Enter 后返回,这不是我想要的。

4

2 回答 2

12

在 Linux 上,getch()可能是curses函数,它与 Windows 特定的同名函数有很大的不同。 curses( ncurses) 对于您想要做的事情来说可能是矫枉过正。

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

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

如果您真的希望用户能够按下任何键,而不仅仅是Enter,您可以执行以下操作:

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

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

编辑:无需等待即可阅读单个字符Enter是一个常见问题。事实上,这是comp.lang.c FAQ中的问题 19.1 。

EDIT2:我最近没有做太多的诅咒工作,但我只是做了一些玩弄它。除非您先致电并清除屏幕,否则这似乎getch()不起作用。curses 旨在与需要完全控制显示的文本编辑器等应用程序一起使用。可能有一种方法可以在不控制屏幕的情况下使用,但我还没有找到。initscr()initscr()getch()

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

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

至于 OP 的评论“我不敢相信Press any key to exit.在 c 中做起来这么麻烦”,是的,这看起来确实很奇怪——但进一步认为这是有正当理由的。

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

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

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

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

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

大多数生产 Unix 程序不使用或不需要Press any key to exit提示。他们只是做他们的工作,通常是默默地,然后终止,这样你就可以做下一件事了。对诸如家庭作业等相对初级的项目的需求主要存在。并不是说家庭作业有什么问题,而是整个系统的主要设计目的并不是支持这种用法。

于 2011-09-14T02:29:55.817 回答
6

这是一个最小的例子

#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;
于 2011-09-14T05:38:51.560 回答