2013-06-05 23 views
5

Chương trình tôi đang xây dựng chạy trong một vòng lặp vô hạn trong khi có trường hợp chuyển đổi trong đó. Tôi muốn chèn một vòng lặp while trong mỗi trường hợp và thực hiện vài thao tác trong vòng lặp, nhưng vòng lặp nên thoát ngay sau khi một đầu vào bàn phím được đưa ra. Vì vậy, sau khi lấy đầu vào từ bàn phím một trường hợp khác được chạy với vòng lặp lồng nhau trong đó, và quá trình tiếp tục.Làm thế nào để phá vỡ một vòng lặp while trong C trên Linux bằng cách lấy bất kỳ giá trị từ bàn phím?

Cấu trúc là:

while()//infinite loop 
    { 
    ...............  //operations 
    ...............  //operations 
    switch() 
     { 
     case 1: 
     ............... //operations 
     ............... //operations 
     while()//infinite loop 
      { 
      .............. 
      .............. 
      exit if there is any input from keyboard 
      } 
     break; 

     case 2: 
     ............... //operations 
     ............... //operations 
     while()//infinite loop 
      { 
      .............. 
      .............. 
      exit if there is any input from keyboard 
      } 
     break; 


     case n: 
     ............... //operations 
     ............... //operations 
     while()//infinite loop 
      { 
      .............. 
      .............. 
      exit if there is any input from keyboard 
      } 
     break; 
     } 
    } 

Có cách nào để làm điều đó ???

+2

Bạn đang hỏi cách nhận đầu vào bàn phím hoặc cách ngắt vòng lặp lồng nhau? – ugoren

+0

Bạn có hỏi làm cách nào để nhập dữ liệu thô, vì vậy việc chờ đợi kết thúc ngay khi _any_ tạo mã char hoặc mã điều khiển được nhấn, thay vì bị ép nhấn enter (sau khi nhập một số văn bản tùy chọn)? – blubberdiblub

+0

Bất kể giải pháp cho vấn đề bàn phím, chức năng này nên được cấu trúc lại. – unwind

Trả lời

0

Cảm ơn bạn người .... mặc dù câu trả lời của tôi là một chút ra khỏi hộp, tôi nghĩ cách tiếp cận của ring0 tốt hơn nhiều. Đây là những gì tôi đã làm.

  • Added mã bên trong bên ngoài vòng lặp while cho phép trình biên dịch để có lập luận đối với trường hợp chuyển đổi từ một tập tin, chẳng hạn, data.dat
  • Nhập mã tương tự trong mỗi lồng vòng lặp while để tiếp tục nếu biến lấy từ data.dat là những gì được yêu cầu để chạy vòng lặp, nếu không, break.
  • Vì trong linux tôi có thể chạy các quy trình ở mặt sau, tôi chạy chương trình chính ở chế độ nền và chỉnh sửa dữ liệu.dat tương ứng.

Phương pháp này làm việc cho tôi nhưng chắc chắn sẽ thử phương pháp của ring0.

6

Đầu vào bàn phím Linux được đệm, để nắm bắt một phím đã được nhấn khi đang di chuyển, bạn phải định cấu hình TERM IO.

gần phía trên cùng của main() thêm một cuộc gọi đến (xem code dưới đây)

term_nonblocking(); 

để đọc một chìa khóa đã được ép một cách nhanh chóng, mà không cần chờ đợi một trở về vận chuyển (CR).

Code:

struct termios stdin_orig; // Structure to save parameters 

void term_reset() { 
     tcsetattr(STDIN_FILENO,TCSANOW,&stdin_orig); 
     tcsetattr(STDIN_FILENO,TCSAFLUSH,&stdin_orig); 
} 

void term_nonblocking() { 
     struct termios newt; 
     tcgetattr(STDIN_FILENO, &stdin_orig); 
     fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); // non-blocking 
     newt = stdin_orig; 
     newt.c_lflag &= ~(ICANON | ECHO); 
     tcsetattr(STDIN_FILENO, TCSANOW, &newt); 

     atexit(term_reset); 
} 

Lưu ý: term_reset() sẽ được gọi tự động khi thoát khỏi chương trình của bạn, (để thiết lập lại các thông số thiết bị đầu cuối).

Bạn có thể gọi hiện nay non-blocking getchar() bất cứ nơi nào trong chương trình của bạn để phát hiện một phím bấm

int i = getchar(); 

và kiểm tra nếu một phím được nhấn:

if (i > 0) { 
    // key was pressed, code in `i` 
} 

Trong chương trình của bạn ví dụ:

int key = 0; 

while (... && key <= 0) { 
    // ... 
    key = getchar(); 
} 

Lưu ý: nếu bạn muốn outpu t là không có bộ đệm, gọi setbuf(stdout, NULL);

(bình luận từ @stacey: getchar() có thể trở về 0 hoặc -1 khi không có chìa khóa có sẵn)

+1

Bạn có thể muốn 'ungetc (i, stdin)' nếu bạn đọc một ký tự sao cho nó có thể được xử lý lại bằng vòng ngoài. –

+0

@JonathanLeffler Cảm ơn. Đây là thông tin có giá trị thực sự. –

+1

Lưu ý rằng getchar() trả về -1 hoặc 0 nếu một phím chưa được nhấn. Tôi đã sử dụng '(key <= 0)' trong điều kiện thời gian của tôi để giải quyết vấn đề này. Khi nó đứng, vòng lặp while kết thúc ngay lập tức nếu không có gì được nhấn. – stanri

0

Tôi đã có một mong muốn tương tự cho một hệ thống cũ mà tôi phải duy trì. Tôi muốn thêm một "bỏ thuốc lá" cũng như cung cấp một số thời gian. Tôi đã loại bỏ tất cả các mã độc quyền và để lại vỏ của những gì tôi đã học được từ trang web này. Cảm ơn bạn.

Tôi đã sử dụng ví dụ trên bằng cách ring0. Tôi muốn bình luận nhưng tôi vẫn chưa ở cấp độ đó.

tôi cũng mất một số thông tin từ here bởi UlfWalter

tôi không thể sử dụng fcntl vì một biến toàn cầu được sử dụng trong mã của chúng tôi rằng mâu thuẫn với một cái gì đó trong fcntl và tôi không muốn tìm ra cách để tránh xung đột đó.

Dù sao, đây là một ví dụ. Nó làm việc cho tôi trên Debian (phiên bản cũ hơn). Số dặm của bạn có thể thay đổi.

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <time.h> 
#include <sys/time.h> 
#include <sys/types.h> 

#define SLEEP 500000. /*usec*/ 

#include <termios.h> 
struct termios stdin_orig; 

void term_reset() { 
    tcsetattr(STDIN_FILENO, TCSANOW, &stdin_orig); 
    tcsetattr(STDIN_FILENO, TCSAFLUSH, &stdin_orig); 
} 

void term_nonblocking() { 
    struct termios term; 
    tcgetattr(STDIN_FILENO, &stdin_orig); 
    term = stdin_orig; 
    term.c_iflag |= IGNBRK; 
    //term.c_iflag &= ~(INLCR | ICRNL | IXON | IXOFF); 
    term.c_lflag &= ~(ICANON);// | ECHO | ECHOK | ECHOE | ECHONL | ISIG | IEXTEN);*/ 
    term.c_cc[VMIN] = 0; 
    term.c_cc[VTIME] = 0; 
    /* fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); // non-blocking */ 
    tcsetattr(STDIN_FILENO, TCSANOW, &term); 
} 
// end mikes timing 

int main (void) 
{ 
    int key=0; 
    // mikes test variables 
    long mnloops = 0; 
    double mttot = 0.0;//total time elapsed in difference between start-end. 
    term_nonblocking(); 
    // end mikes test variables 

    /*main loop*/ 
    do{ 
    //mikes timing 
    puts("Start Do"); 
    time_t mnow; 
    struct timeval mtv; 
    struct timezone mtz; 
    time(&mnow); 
    gettimeofday(&mtv, &mtz); 
    double startTime = (double)mnow + mtv.tv_usec/1e6; 
    // end mikes timing 
    usleep(SLEEP); 
    puts("got hey"); 
    //mikes timing 
    time(&mnow); 
    gettimeofday(&mtv, &mtz); 
    mttot += (((double)mnow + mtv.tv_usec/1e6) - startTime); 
    mnloops++; 
    key = getchar(); 
    // end mikes timing 
    }while (1 && key != 'q');/* end of main loop*/ 
    term_reset(); 
    printf("DONE: average time per loop = %-10.4e\n",mttot/mnloops); 
    return 0; 
} 
Các vấn đề liên quan