• 締切済み

Linuxで入力待ちなしkeyread関数のようなものはありますか?

Fookyの回答

  • Fooky
  • ベストアンサー率71% (59/82)
回答No.3

入力待ちなしでキーを読むにはO_NONBLOCKフラッグを セットすればOKです。これにより、read()関数やscanf() 関数を呼び出しても、キー入力があるまでそこで 止まる(ブロックされる)ことが無くなります。 あるファイルにO_NONBLOCKをセットするには、 terra5さんが言うように、 open("/dev/tty", O_RDONLY|O_NONBLOCK); でそのファイルをオープンします。 標準入力のように、既に開いてしまっているファイルに 対しては、 fcntl(0, F_SETFL, O_NONBLOCK); です。 読み込みもterra5さんの通りです。 ただ、これだとリターンキーが押されるまで 入力なしとみなされます。 リターンキーを押さなくても1文字ずつ入力を 受けたい場合、もう一工夫要ります。 標準入力のターミナル属性を操作することでnon-canonical モードにして、ターミナルのバッファリングを停止します。 詳しくは、tcgetattr(), tcsetattr(), termiosなどの manページを見てください。 ただ、nabezo-さんの仰るようにスレッドにして、 そのスレッドを入力待ちの間ブロックしたほうが、 入力待ち以外の仕事が少ない場合は、 CPU負荷が減って良いことがあります。 (逆にそうしないとビジーウェイト状態になって、CPU  負荷が異様に上がります) #include <stdio.h> #include <unistd.h> #include <termios.h> #include <signal.h> #include <errno.h> static void post_proc(int); static struct termios SavedTermAttr; int main(int argc, char **argv) {  char c;  signal(SIGINT, &post_proc);  struct termios term_attr;  /* Terminal control */  /* ファイルディスクリプタ0(標準入力)   のターミナル属性を取得 */  if( tcgetattr(0, &term_attr) < 0 ){   fprintf(stderr, "Can't get terminal attributes.\n");   post_proc(-1);  }  /* 取得したターミナル属性を保存 */  SavedTermAttr = term_attr;  /* ICANON、ECHOフラッグをセット */  term_attr.c_lflag &= ~(ICANON|ECHO);  /* 入力文字列の最小読出バイト数を1に */  term_attr.c_cc[VMIN] = 1;  /* 入力待ち時間を0に */  term_attr.c_cc[VTIME] = 0;  /* 変更したターミナル属性をセット */  if( tcsetattr(0, TCSANOW, &term_attr) < 0 ){    fprintf(stderr, "Can't change terminal attributes.\n");    post_proc(-1);   }  /* NONBLOCKフラグのセット */  if( fcntl(0, F_SETFL, O_NONBLOCK) == -1 ){   fprintf(stderr, "Can't fcntl().\n");   post_proc(-1);  }  /* Main loop */  while(1){   while( read(0, &c, 1) != 1 )    if( errno != EAGAIN ){     fprintf(stderr, "EOF\n");     post_proc(0);    }   printf("%c\n", c);  } } void post_proc(int sig) {  /* 保存されたターミナル属性を復元 */  if( tcsetattr(0, TCSANOW, &SavedTermAttr) < 0 ){   fprintf(stderr, "Can't change terminal attribute.\n");   exit(-1);  }  if( sig < 0 )   exit(-1);  else   exit(0); }

関連するQ&A

  • 特定の文字が入力されるまで・・・

    プログラムで、 A~Cの記号が選ばれるまで、 (つまり他の文字が入力されたらもう一度入力しなすようにしたい) 入力コマンドを繰り返す制御文を作りたいのですが 自分で作ってもうまくいきません。 char c; while((c=getchar())!='A'||'B'||'C'){ } 以下はA,B,Cのいずれかが入力されたら実行される制御文が続く しかし、実際はA~Cを入力しても、 次の制御文に移りません。 どこがおかしいでしょうか? また、正しく動かすにはどうすればよいでしょうか?

  • whileの途中で手続きを変化するプログラム

    表題の件について質問させていただきます。 while(1)を含むプログラムを走らせている途中で何かしら入力するとそれに伴って処理を変更するプログラムを作成したいと思います。 具体的には ・qを押せばCtrl+cとは違い、正常な手続きを持ってプログラムを終了する。 ・押したキーに従い、while(1)文の中で呼び出される関数を変更する。 といったことを行いたいです。 このようなことは可能なのでしょうか? ご指導をお願いいたします。

  • scanf関数について

    こんなプログラムがありました。 char str[80]; while(scanf("%s",str)>=1){    ・・・  } このwhileループは何が入力されたときに終了するのですか?scanf関数は入力された文字を返り値に持つとわかったので、改行コードを入力しましたが、終了しませんでした。どうすればよいのでしょう。よろしくお願いいたします。

  • 伝達関数の求め方について(2入力2出力系)+圧力の制御

    はじめまして。拙い説明ですがお願いします。 実測値から伝達関数を求めたいのですが、2入力2出力系の時はどうすればよいのか分らず困っています。 実験では、入力は圧力で出力は位置です。入力(圧力)1,2の相互作用で出力(位置)1,2が変わってしまいます。 Q1.この際、伝達関数は4つ求めるのでしょうか? また、根本的に入力である圧力が非線形です。制御の流れを、 (例)パソコン→DA変換→圧力→[ ]→位置 とした場合、制御するためには Q2.圧力に対する位置の伝達関数を求めるべきか、もしくは パソコンの入力値に対するシリンダ内の圧力の伝達関数をプラスして求めるべきなのでしょうか?

  • C言語のプログラムみてください(isdigit)

    質問は2つあります。 (1) scanf関数を使って、 時給: と表示されたところに一文字打ち込み、数字以外ならばもう一度 時給: と表示されるプログラムを作りたいです。 以下のプログラムなら、 isdigit関数は数字を渡せば0以外の数を返す(真)から、 while文の条件式(偽)のようにすれば、 ・数字を一文字うちこめばwhile文の条件式にあてはまらない、すなわち下のプログラムではisdigit(payment) != 0 となり、return 0; が実行され、プログラムが終わる ・数字以外を一文字打ち込めばwhile文の条件式が真となり、printf関数とscanf関数が実行されて入力待ち状態になる と思ったのですが、どうやら違うようです。実際には ・数字一文字打てばまた入力待ちになる ・数字以外を一文字打てば永遠にprintf関数とscanf関数が実行される のはなぜでしょうか。 #include <stdio.h> #include <ctype.h> int main(void){ int payment; do{ printf("時給[円]:"); scanf("%d",&payment); } while (isdigit(payment) ==0) ; return 0; } (2) 実際には、一文字の制限なく、数字以外の何かを入力したら、再び入力待ちになるプログラムを作りたいのですが、これはどうしたらいいのでしょうか。 つまり 時給: のところに数字以外ならまた 時給: となるようにしたいのです。お願いします。

  • Linuxでリアルタイム制御するには

    PCからAD/DAボードを介して小型のロボットをリアルタイム制御したいと思っています.これまではWindowsPCにMATLABをいれて,MATLABでプログラムを作って制御していたのですが,LinuxでMATLABを使わずにリアルタイム制御したいと思っています. そこで質問ですが,Linuxでリアルタイム制御するには,どのようなOSが必要なのでしょうか?Ubuntuで大丈夫でしょうか?また,PCにはOSの他に何を入れる必要があるのでしょうか?(これまではWindowsPCにMATLABとそのToolBoxを入れるだけでリアルタイム制御していたので,それ以外のやり方について全くの無知です.) アドバイス頂ければ幸いです.よろしくお願い致します.

  • ダメだ・・・分からない。while文 無限ループ&’\n’エンター後無限ループ脱出

    忙しい中失礼します。 C言語超初心者のものです。while文での表示について質問があります。 下記の’プログラム内容’はEnterキーが押されるまで、 ’k’入力後 → Enterキー → ASCII value of k is 107.  ’t’入力後 → Enterキー → ASCII value of t is 116. ・・・ のように継続させ、 何もアルファベットを記入せず、’Enterキー’のみを押した場合はループから抜け、DOS画面を終了するようにしたいのですが、それが出来ません・・・。 ’k’入力後Enterキーを押すと、’Enter a character:’の表示がなされた後、’Press any key to continue・・・’となり画面を閉じなければいけなくなります。 while文の中の()内を何とかすれば、思い通りのプログラムになる、とは思うのですが、それが考え付きません。 申し訳ありませんが、よろしければそのヒントを下さい。多分すごく簡単なことだとは思うのですが、それが出来ません。 ※私個人の考えとしては、while文の中の(scanf("%c", &ch)&&(ch!='\n'))において、’&&(ch!='\n')’をプログラム文からなくせば、Enterキーを押さない限り(’k’入力後のEnterキー除く)、何度もパソコン側から尋ねられると思ったのですが・・・。・・・うまくいかず。 プログラミング内容: #include <stdio.h> #include <stdlib.h> int main() { char ch; printf("Enter a character:\n"); while(scanf("%c", &ch)&&(ch!='\n')) { printf("ASCII value of %c is %d.\n\n", ch, ch); printf("Enter a character:\n"); } system("PAUSE"); return 0; }

  • Linuxのgccでセマフォをやりたい。

    gccプログラムでマルチタスクのプログラミングをやっています。 https://sourceforge.jp/projects/cc1101driver/scm/svn/blobs/2433/trunk/20140411/main.c 以前、H8マイコンに組み込みOSを使用した際に、複数のタスクを動作させている際に、各タスクがwhile(1)で永久ループの状態をしている際に、その永久ループを一時停止するためのロック・アンロック専用のタスクを1つ作って、各タスクのロック・アンロックして動作を制御することをやったことがありました。 確かロックの場合はSempend();というので、アンロックというのはSempost();という物だったと思いました。 例えばTASK1,TASK2,TASK3という3つのタスクを作成し、それぞれを制御したい場合は、 例えばTASK1のセマフォをアンロックしたい場合は Sempost(LockTask1); このようにしたらTASK1が動作し始め、ロックしたい場合はSempend(LockTask1);というようにしたいと思います。 次の例のようなセマフォ制御をLinuxのgccのセマフォプログラミングで行うことは可能でしょうか? どうぞ、ご教示頂きますようお願い致します。 (例) //タスクセマフォ制御用タスク TASK_SEM_CTL() { while(1) { Sempost(LockTask1); delay(1000) //1sec wait Sempost(LockTask2); delay(1000) //1sec wait Sempost(LockTask3); delay(1000) //1sec wait } } TASK1 { while(1) { Sempend(LockTask1); printf("TASK1_done"); Sempost(LockTask1); } } TASK2 { while(1) { Sempend(LockTask2); printf("TASK2_done"); Sempost(LockTask2); } } TASK3 { while(1) { Sempend(LockTask3); printf("TASK3_done"); Sempost(LockTask3); } }

  • 4桁の数字以外を入力したらエラーを表示したいです

    if文とwhile(for)文の範囲の課題で4桁の数字を入力してどうこうというプログラムを作っています。 課題には書かれていませんが、4桁の数字以外を入力したときにエラーを表示させるにはどんな方法がありますか? 10000以下をはじけばいいんじゃないかと思ったのですが、これだと「0001」などもはじかれてしまうようでして、アルファベットや記号が含まれるものも同時にはじきたいのですが、何か良い方法がわかる方いましいたら、ぜひ解説をお願いします。 なお課題では、理解していれば習っていない関数も使っていいと書かれていました。こんな関数を使ってみては?というものがあれば教えていただけるとうれしいです。

  • ループの特定入力終了

    C言語初心者です。よろしくお願いします。 whileなどのループ関数を使って、キーボード 入力をするたびに、ループが一度走る事は、 可能です。ですが、 常にループは走らせながらendなどの特定 の入力をされた場合に、ループを抜ける プログラムをどうしてもできません。 わかる方、教えていただければ幸いです。