Auswertung von Zeicheneingaben in Iterationen (Schleifen)
-
Hallo COM,
Hab da gerade folgendes Problem.
Mir geht es einfach darum, in einer iterierenden Schleife hin und wieder per Tastendruck (egal welche) ein Zwischenergebnis ausgeben zu lassen. Die Schleife soll aber munter weiterlaufen.
Hier mein Bsp.-Code:#include <climits> #include <cstdint> #include <cinttypes> #include <cfloat> #include <cmath> #include <cstdlib> #include <cstdio> #include <stdio.h> #include <iostream> #include <string.h> #include <termios.h> using namespace std; int my_getch() { static int ch = -1, fd = 0; struct termios neu, alt; fd = fileno(stdin); tcgetattr(fd, &alt); neu = alt; neu.c_lflag &= ~(ICANON|ECHO); tcsetattr(fd, TCSANOW, &neu); ch = getchar(); tcsetattr(fd, TCSANOW, &alt); return ch; } int my_kbhit(void) { struct termios term, oterm; int fd = 0; int c = 0; tcgetattr(fd, &oterm); memcpy(&term, &oterm, sizeof(term)); term.c_lflag = term.c_lflag & (!ICANON); term.c_cc[VMIN] = 0; term.c_cc[VTIME] = 1; tcsetattr(fd, TCSANOW, &term); c = getchar(); tcsetattr(fd, TCSANOW, &oterm); if (c != -1) { ungetc(c, stdin); } return ((c != -1) ? 1 : 0); } int main(int argc, char *argv[]) { uint64_t Var29 = 0, tmp29 = 1; for(;tmp29 > 0;tmp29++) { Var29++; if(my_kbhit()) { if(my_getch()=='c') { printf("x: %"PRIu64"\n",Var29); } } } getchar(); return 0; }In dem Fall lasse ich einfach die IF-Bedingung war werden, wenn ich die Taste "c" drücke. Kann meinetwegen auch irgendeine sein.
Das Problem dabei, die Schleife iteriert nun arg langsam. Das sie fleißig weiteriteriert, kann man sehen, wenn man mal in unterschiedlichen Zeitintervalen "c" drückt.
Außerdem kann ich nun drücken, was ich möchte, kann aber nicht das Prog anhalten. Üblicherweise halte ich einfach mit STRG+C an. @Moment muss ich immer mit pidof und kill hantieren.
Weiß einer, wie ich denn richtig abfragen müsste, damit:
a.) Die Schleife trotz If-Abfrage, Aufruf von my_kbhit() und my_getch() weiterhin schnell iteriert (ohne IF-Abfrage-[Inhalt] ist die Schleife beendet, wie ich das Programm gestartet habe, also sehr sehr schnell und dass bei einer Inkrementierung bis Maximum von __int64_t)?
b.) Ich weiterhin mit STRG+C das Programm beenden kann.THX im Voraus!
Grüße
Schlitzauge

-
Benutze statt der Eingabe von Tastatur Signale.
.. ist die Schleife beendet, wie ich das Programm gestartet habe ..
Vielleicht hat der Compiler die Schleife wegoptimiert. Bei etwa 2Ghz schafft der Prozessor vielleicht in einer Sekunde bis 2^31 zu zaehlen. Demnach sollte er etwa 2^32 Sekunden benoetigen, um bis 2^64 zu zaehlen.
-
Interessanterweise spielt es gar keine so große Rolle, dass du bei jedem Schleifendurchlauf wieder die Terminal-Settings zweimal veränderst; das eigentliche Problem ist getchar(), welches scheinbar eine Weile auf Daten wartet.
Wir bewegen uns hier eh abseits des C++-Standards, also greife ich mal in die POSIX-Kiste: fcntl und read sind dein Freund für non-blocking IO. Ich stelle mir das etwa so vor:
#include <cstdio> #include <iostream> #include <limits> #include <tr1/cstdint> #include <termios.h> #include <unistd.h> #include <fcntl.h> int main() { // Terminal-Settings so verändern, dass die Eingabe ungepuffert und ohne // Echo erfolgt: struct termios ts_old, ts_new; tcgetattr(STDIN_FILENO, &ts_old); ts_new = ts_old; ts_new.c_lflag &= ~(ICANON | ECHO); tcsetattr(STDIN_FILENO, TCSANOW, &ts_new); // Stdin auf non-blocking setzen int stdin_flags = fcntl(STDIN_FILENO, F_GETFL); fcntl(STDIN_FILENO, F_SETFL, stdin_flags | O_NONBLOCK); for(std::tr1::uint64_t i = 1; i > 0; ++i) { char c; if(read(STDIN_FILENO, &c, 1) == 1 && c == 'c') { std::cout << "i: " << i << std::endl; } } // Hinterher aufräumen. In Produktionscode sollte das natürlich per RAII // gemacht werden. fcntl(STDIN_FILENO, F_SETFL, stdin_flags); tcsetattr(STDIN_FILENO, TCSANOW, &ts_old); return 0; }Es wird trotzdem ewig dauern, bis ein uint64_t überläuft. Das kann ich aber auch nicht ändern.
Was Ctrl-C angeht: dass das nicht funktioniert, wird daran liegen, dass du hier:
term.c_lflag = term.c_lflag & (!ICANON);c_lflag völlig ausradierst, weil du den Binärkomplement-Operator mit dem logischen Nicht-Operator verwechselst. Dabei wird auch ISIG auf 0 gesetzt, und dementsprechend generiert Ctrl-C kein SIGINT mehr.