いま練習として簡単な計測器の制御プログラムを作っていまして、
while文で計測させて、何かキーを押すと抜けだすような制御を
したいのです。
調べたところ、dos.hを用いたkeyread関数というものでできそう
だったのですが、Linux上ではできないようなのです。
ほかに、入力待ちなしでキーを読む方法を知っている方がいたら
すみませんがどうぞお教えください。よろしければ簡単なプログラム例など書いていただければ幸いです。

A 回答 (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);
}
    • good
    • 2

#「素人」からのコメントですが、ご了承ください。


#(cursesライブラリを使ったことがあります)

cursesライブラリに、getch()という関数があります。
キーボードからの入力待ちなどに使います。

「while文で計測させて、何かキーを押すと抜けだすような制御」
とあるので、スレッドを作成して、そのスレッドで計測させては
駄目ですか?
getch()が戻ってきて、入力されたキーをチェックして、
計測を終了させるためのキーだと判断したら、while()を
終了させてあげる条件(フラグなど)をセットするとか、、、

#「入力待ちなしでキーを読む」というのがちょっと理解できなかったので
#期待されている回答ではないかもしれませんね。
    • good
    • 0

非同期モードにしてi/oすれば可能だろうと思います。



例えば,

int f=open("/dev/tty", O_RDONLY|O_NONBLOCK);
char c;

if ( read(f,&c,1) == 1 ) {
/* キー入力があった */
} else }
/* キー入力がなかったか、エラー */
}

みたいなので・・・。
コンパイルもしていないので、あとはマニュアルで(^^;

dos.hはMS-DOS用のですね。

あとは、cursesにそういう関数かマクロがあったような記憶が。
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Q外部プログラムを実行してそのプログラム中のキー入力を自動で行うにはどうしたらいいか?

現在C++でプログラミングを組んでいるものです。

外部プログラムを実行させ、外部プログラム実行中に求められるキー入力を自動で行えないかと考察しているのですがわかりません。。。
外部プログラムといっているのは、現在C++で書いていて
その中でsystemコマンドを使い他のexeを実行しているので。

求められるキー入力はDOS窓の画面で
------------------------------------
上記の設定でよろしいでしょうか?> y
------------------------------------
上記の『y』の箇所のみで『y』+Enterでその後の処理が走り出すというもので、毎回聞かれる『y』の入力を自動化したいのですが
何か方法は無いものでしょうか??

exeファイルしかなく修正もできないのでなんとか自動的に入力まで含められないかと考えてます。

みなさんどうぞよろしくお願いします。

Aベストアンサー

標準入力を使う方法なら、

y.txt
y

という内容のファイルを作成しておき、

○○.exe < y.txt

では?

Qwhile for/ if else/do while文を使い”640968592”の各数字を独立させて取り出すことは可能でしょうか?

忙しい中失礼します。

今以下のようなプログラミングを組もうとしています。
1.”640968592”といった9桁の数字を入力→scanfで入力(これは出来ます)
2.各桁の数字を独立させて取り出す:”6” ”4” ”0” ”9” ”6”・・・といった具合に(これも一応出来ます)
3.偶数桁は2倍する
  2桁目:4x2=8
  4桁目:9x2=18
  6桁目:8x2=16
  8桁目:9x2=18

そして、私の場合、以下のようなプログラムになるのですが、これがなんとも不細工な感じがし、スマートにプログラムを変更したいと思っています。

抱えている問題:while for/ if else/do while文などを用いて、下記のプログラムを書き直すことは可能なのでしょうか?例え出来たとしても、文int=num1~num35までの定義も減らすことは可能なのでしょうか?
手も足も出ない・・・

プログラム内容
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main()
{
int num1,num2,num3,num4; /*8 9桁目*/
int num5,num6; /*7桁目*/



int num15,num16; /*2桁目*/
int num17; /*1桁目*/
int num19,num20,num21,num22,num23,num24,num25;
int num26,num27,num28,num29,num30,num31,num32;
int num33,num34,num35;


printf("Write the SIN: ");
scanf ("%d", &num1);

num2=num1 / pow(10, 8); //9桁目

num3=num1 / pow(10, 7); //8桁目
num4=num3 % 10;

num5=num1 / pow(10, 6); //7桁目
num6=num5 % 10;



num15=num1/pow(10, 1); //2桁目
num16=num15%10;

num17=num1%10; //1桁目

num19=num4*2; //8桁目計算
num20=num19/10;
num21=num19%10;
num22=num20+num21;



num31=num16*2; //2桁目計算
num32=num31/10;
num33=num31%10;
num34=num32+num33;

system("pause");

return 0;
}

こんなのが直ぐにプログラムとして早く組めるようになりたい・・・


どうしても頭に浮かばないのです。アドバイス等あればお願いします。

<使用環境:フリーソフト(Borland?)C ANSI C>

忙しい中失礼します。

今以下のようなプログラミングを組もうとしています。
1.”640968592”といった9桁の数字を入力→scanfで入力(これは出来ます)
2.各桁の数字を独立させて取り出す:”6” ”4” ”0” ”9” ”6”・・・といった具合に(これも一応出来ます)
3.偶数桁は2倍する
  2桁目:4x2=8
  4桁目:9x2=18
  6桁目:8x2=16
  8桁目:9x2=18

そして、私の場合、以下のようなプログラムになるのですが、これがなんとも不細工な感じがし、スマートにプログラムを変更したいと思っています...続きを読む

Aベストアンサー

プログラム的にはほぼ合っていますが、ループ化するには向きません。
間違いは、ケタが1ketame~3ketameと書いてあるが逆。

ループ化する布石として、
・なるべく数値を直接使わないで変数から求めるようにする。
1ketameとかは、%dketameで変数からケタを表示する。
/100なら、/ pow(10,変数)で計算する。
両方とも、変数ketaから求められますよね。
keta=3;を初期値として、keta--;で減算しながら書いてみてください。
ketanumも3つでは無く1つの変数で処理します。毎ケタ毎残す必要が無ければ同じ変数を使って良いんです。

できあがったプログラムを見てください。同じような処理の繰り返しでループ化できそうになりませんでしたか?

Qswitch文とwhile文を用いたプログラムに関して

swich文とwhile文を用いたプログラムについて

授業の課題で、swich文とwhile文を用いたプログラムを作りなさい。いう課題が出ました。

5桁以上9桁以下の正の整数を入力し、4で割り切れたとき、何桁の数字かを出力。4でわって1余ったとき、すべての桁の合計を出力。3余ったとき、与えられた数の逆を変数に代入し、その変数を出力(単純に表示するわけではなく、数字として表示)

といったものです。
途中からの授業参加で、C言語に関する知識はほとんどありません。do文を用いたプログラムは見つけれたのですが、while文とswich文を用いろということなので、do文は使えないです。

どなたか教えていただけませんか?
今日中にわからないとちょっとやばいです・・・。
よろしくお願いします

Aベストアンサー

こんな感じでいいのかな?

#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "math.h"

int main(int argc, char* argv[])
{

char sInput[32];
int iInput=0;
int iLen=0;
int iMod=0;
int iSum=0;
int iReb=0;
int iCnt=0;
char sBuf[32];

memset(sInput,0,sizeof(sInput));
memset(sBuf,0,sizeof(sBuf));
scanf("%s",&sInput);
iLen = strlen(sInput);

if( iLen > 9 || iLen < 5 )
{
printf("対象桁数外");
return 0;
}

iInput = atoi(sInput);

iMod = iInput % 4;

switch(iMod)
{
case 0:
printf("入力された数字は %d 桁です。",strlen(sInput));
break;
case 1:
while(iCnt < iLen)
{
sprintf(sBuf,"%c",sInput[iCnt]);
iSum += atoi(sBuf);
iCnt++;
}
printf("入力された数字の合計は %d です。",iSum);
break;
case 3:
iReb = 0;
while(iCnt < iLen)
{
iCnt++;
sprintf(sBuf,"%s%c",sBuf,sInput[iLen-iCnt]);
}
iReb = atoi(sBuf);
printf("入力された数字の逆順は %d です。",iReb);
break;
}
return 0;
}

こんな感じでいいのかな?

#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "math.h"

int main(int argc, char* argv[])
{

char sInput[32];
int iInput=0;
int iLen=0;
int iMod=0;
int iSum=0;
int iReb=0;
int iCnt=0;
char sBuf[32];

memset(sInput,0,sizeof(sInput));
memset(sBuf,0,sizeof(sBuf));
scanf("%s",&sInput);
iLen = strlen(sInput);

if( iLen > 9 || iLen < 5 )
{
...続きを読む

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

表題の件について質問させていただきます。

while(1)を含むプログラムを走らせている途中で何かしら入力するとそれに伴って処理を変更するプログラムを作成したいと思います。

具体的には
・qを押せばCtrl+cとは違い、正常な手続きを持ってプログラムを終了する。

・押したキーに従い、while(1)文の中で呼び出される関数を変更する。

といったことを行いたいです。
このようなことは可能なのでしょうか?
ご指導をお願いいたします。

Aベストアンサー

関数へのポインタを使って、

///////////////////////////////////////////
typedef void ( * mfunc ) ( void ) ;

void func1();
void func2();
void func3();

mfunc pfunc = func1; /* デフォルト func1 */
int fin = 0; /* 1なら終了処理を行う */

while(1){

 /* 押されたキーに応じて実行する関数を切り替える */
 if( kbhit() ){
  c = getch();
  switch(c){
  case 'p':
   pfunc = func2; /* 関数へのポインタを付け替える */
   break;

  case 'q':
   fin = 1; /* while を抜けて終了処理にすすむ */
   break;

  case 'r':
   pfunc = func3; /* 関数へのポインタを付け替える */
   break;

  default:
   pfunc = func1; /* 関数へのポインタを付け替える */
   break;
  }
 }

 if( fin ){
  break;   /* 終了処理に進む */
 }
 else{
  pfunc();  /* 関数を実行する */
 }
}

/* 終了処理 */
ほげほげ;

////////////////////////////////////////

こんなつくりなら、

> ・qを押せばCtrl+cとは違い、正常な手続きを持ってプログラムを終了する。
> ・押したキーに従い、while(1)文の中で呼び出される関数を変更する。

を満足できますよね。

関数へのポインタを使って、

///////////////////////////////////////////
typedef void ( * mfunc ) ( void ) ;

void func1();
void func2();
void func3();

mfunc pfunc = func1; /* デフォルト func1 */
int fin = 0; /* 1なら終了処理を行う */

while(1){

 /* 押されたキーに応じて実行する関数を切り替える */
 if( kbhit() ){
  c = getch();
  switch(c){
  case 'p':
   pfunc = func2; /* 関数へのポインタを付け替える */
   break;

  case 'q':
  ...続きを読む

QC言語のwhile文を使った素数判定プログラムで…

次に示すプログラムは、100までの素数を表示するものです。
見てのとおり、C言語のwhile文を使って書いてあります。

#include <stdio.h>

int main(void)
{
int a, b;
int flag = 0;

a = 2;
b = 2;

while(b <= 100){

*ここ*

while(a < b){

if(b%a == 0){
flag = 0;
break;
}

else{
flag = 1;
}

a++;
}

if(flag == 1){
printf("%dは素数\n", b);
}

b++;
}


getch();
return 0;
}

最初、手本を参考にしながら上記のように書きましたが、うまく機能せず、3から100までの数字すべてが素数であると表示されました。
どこが間違っているのかと、手本と厳密に見比べてみたら、8行目の
a = 2
が*ここ*と書いてある場所に書かれていました。
まさかないだろうと思いつつ、もとあったのを消して*ここ*に書き換えたら、正しく素数が表示されるようになりました。
値を代入する場所が違うだけで、なぜこのような違いが起こるのか全く理解できません。
教えてください。
(一応、書いておきますが使っているコンパイラはBorlandのやつです
コンパイラのせいってことはないですよね)

次に示すプログラムは、100までの素数を表示するものです。
見てのとおり、C言語のwhile文を使って書いてあります。

#include <stdio.h>

int main(void)
{
int a, b;
int flag = 0;

a = 2;
b = 2;

while(b <= 100){

*ここ*

while(a < b){

if(b%a == 0){
flag = 0;
break;
}

else{
flag = 1;
}

a++;
}

if(flag == 1){
printf("%dは素数\n", b);
}

b++;
}


getch();
return 0;
}

最初、手本を参考にしながら上記のように書きましたが、うまく機能せず、3...続きを読む

Aベストアンサー

>つまり、a = 2 はwhileの{}に入れないといけないということで、あってますか?

はい。

#2は無視か,flag = 1の誤り(変数の初期化時も)。勘違いしていた,すまん。

>下のほうは、なぜ値が増えていかないのですか?
毎回
a=0;
が実行されるから。

#1の「階乗」とは言わないだろうな。なんと言うか思いつかんけど。


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング

おすすめ情報