为什么 getch() 在按任何键之前就返回?
- 2024-11-11 08:27:00
- admin 原创
- 23
问题描述:
int main(int argc, char *argv[], char *env[])
{
printf("Press any key to exit.
");
getch();
return 0;
}
根据手册页,
getch
应该等到按下任意键
...但实际上它在按任何键之前直接返回。(返回的值是-1
)。
为什么?
更新
我在 Linux 上。Press any key to exit.
如果不使用,我该如何实现getch()
?
getchar()
按下Enter后才会返回,这不是我想要的。
解决方案 1:
在 Linux 上,getch()
可能是curses
函数,它与同名的 Windows 特定函数有很大不同。 curses
( ncurses
) 可能对于您想要做的事情来说有点小题大做。
最简单的方法是等到用户按下Enter
,您可以这样做:
int c;
printf("Press <enter> to quit: ");
fflush(stdout);
while ((c = getchar()) != '
' && c != EOF) {
/* nothing */
}
如果您确实希望用户能够按任意键,而不仅仅是Enter
,您可以执行以下操作:
system("stty cbreak -echo");
getchar();
system("stty cooked echo");
第二个stty
目的是将 tty 恢复到合理的设置(它应该真的将它们恢复到原来的状态,但保存和恢复状态有点复杂)。可能有更简洁的方法来实现这一点(使用程序stty
本身使用的任何库函数)。
编辑:不等待就读取单个字符Enter
是一个常见问题。事实上,这是comp.lang.c FAQ中的问题 19.1 。
编辑 2:我最近没有用过 curses,但我只是玩了一下。除非你先调用-- 并清除屏幕,否则它似乎getch()
不会起作用。curses 旨在用于需要完全控制显示的应用程序(如文本编辑器)。可能有一种方法可以在不控制屏幕的情况下使用,但我还没有找到。initscr()
`initscr()`getch()
实际上,这个system("stty ...")
临时解决办法可能才是最好的办法。
EDIT3:termios
另一个答案中的解决方案可能是最好的(更system("stty ...")
简单,但调用外部程序感觉有点小题大做。
至于 OP 的评论“我不敢相信Press any key to exit.
用 c 来实现这么麻烦”,是的,这确实看起来很奇怪——但进一步思考后发现这是有充分理由的。
看一下典型的 Unix 或 Linux 系统上安装的程序。我想你会发现它们中很少有程序需要这种输入(等待一次按键)。
许多程序使用命令行参数和从文件或 读取的数据stdin
。用户输入的任何内容都是输入数据,而不是命令或对提示的响应。
有些程序确实会要求确认某些操作(安装程序喜欢apt-get
并cpan
经常这样做)——但它们通常会读取一行输入并检查第一个字符。或者,对于某些激烈的操作,它们可能会要求您输入整个单词“yes”,然后输入Enter
(您不会想因为不小心按到某个键而重新格式化硬盘)。
当然,许多程序(文本编辑器、文件查看器)读取单字符无回显输入,但此类程序往往基于 curses;它们控制整个终端窗口。
最后,许多程序都有 GUI 界面(Web 浏览器等);它们甚至可能不从标准输入读取。
大多数生产 Unix 程序不使用或不需要Press any key to exit
提示。它们只是默默地完成工作,然后终止,以便您可以做下一件事。这种需求主要存在于相对基本的程序中,例如家庭作业。并不是说家庭作业有什么问题,而是整个系统主要不是为支持这种用法而设计的。
解决方案 2:
这是一个简单的例子
#include <curses.h>
int main(){
initscr();
cbreak();
noecho();
printw("Press any key to continue.");
refresh();
getch();
endwin();
return 0;
}
但似乎没有办法在不清除屏幕的情况下使用 ncurses。也许是 Overkill 的污点?!
编辑
这是我发现的另一种方法。这种方法不使用诅咒,也不清除屏幕。
#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;
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件