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");

2 つ目sttyは、tty を適切な設定に復元することを目的としています (実際にはそれらを元の状態に復元する必要がありますが、状態の保存と復元はもう少し複雑です)。おそらく、それを行うためのよりクリーンな方法があります(sttyプログラム自体が使用するライブラリ関数を使用します)。

編集:待機せずに単一の文字を読み取ることEnterは、よくある質問です。実際、これはcomp.lang.c FAQの質問 19.1です。

EDIT2:最近、curses を使った作業はあまりしていませんが、ちょっと遊んでみました。最初に呼び出して画面をクリアしgetch()ない限り、機能しないようです。curses は、表示を完全に制御する必要があるテキスト エディターなどのアプリケーションで使用することを目的としています。画面を制御せずに使用する方法があるかもしれませんが、私は見つけていません。initscr()initscr()getch()

クラッジは実際には最良のsystem("stty ...")アプローチかもしれません。

EDIT3:他の回答のtermios解決策はおそらく最良です(system("stty ...")より簡単ですが、外部プログラムを呼び出すのはやり過ぎのように感じます.

OPのコメント「Press any key to exit.Cで行うのがとても面倒だとは信じられない」については、はい、それは奇妙に思えますが、さらに考えてみると、それには正当な理由があります。

典型的な Unix または Linux システムにインストールされているプログラムを見てみましょう。この種の入力 (キーを 1 回押すのを待つ) を必要とするものはほとんどないことがわかると思います。

多くのプログラムは、コマンド ライン引数と、ファイルまたは .xml から読み取ったデータを使用して動作しますstdin。ユーザーが入力するものはすべて入力データであり、コマンドやプロンプトへの応答ではありません。

一部のプログラムは、いくつかのアクションに対して確認を求めます (インストーラーはこれを好みapt-getcpanしばしばこれを行います)。ただし、通常は入力を読み取り、最初の文字をチェックします。または、いくつかの抜本的なアクションの場合、「はい」という単語全体を入力し、その後に続けて入力する必要がある場合がありますEnter(誤ってキーを押したためにハード ドライブを再フォーマットしたくない場合)。

もちろん、多くのプログラム (テキスト エディター、ファイル ビューアー) は 1 文字の非エコー入力を読み取りますが、そのようなプログラムは curses ベースである傾向があります。それらは端末ウィンドウ全体を制御します。

最後に、多くのプログラムには GUI インターフェース (Web ブラウザーなど) があります。彼らはおそらく標準入力からさえ読んでいません。

Press any key to exitほとんどの本番 Unix プログラムは、プロンプトを使用しないか、または必要としません。彼らは、多くの場合黙って仕事をし、その後終了するので、次のことができます。宿題などの比較的初歩的なプログラムが主に必要とされています。宿題に何か問題があるわけではありませんが、システム全体として、そのような使用法をサポートするように設計されているわけではありません。

于 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 を使用する方法はないようです。もしかしてやり過ぎの染み?!

編集

これが私が働いた別の方法です。これは curses を使用せず、画面をクリアしません。

#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 に答える