2016-04-12 16 views
5

Was macht getch inhärent unportabel, um als Standard-C-Funktion aufgenommen zu werden?Warum ist Getch nicht tragbar?

Es ist so intuitiv und elegant für Konsolenschnittstellen. Ohne sie ist die Frage nach einem einzelnen Zeichen immer irreführend, da Benutzer mehr als einen Schlüssel eingeben dürfen.

Schlimmer noch, Sie müssen oft sicherstellen, dass die Standardeingabe nach dem Lesen der Konsoleneingabe gelöscht wird, was nicht einmal als Standardfunktion zur Verfügung steht! Ich muss meine eigenen benutzen!

Ein einfaches Programm, das sein könnte:

#include <stdio.h> 
#include <stdlib.h> 
#include <ctype.h> 
#include <conio.h> 

int main(int argc, char **argv) 
{ 
    while (1) { 
     char yes_or_no;   

     printf("is this statement correct? 1 + 1 = 2(Y/N) $ "); 
     yes_or_no = tolower(getch()); 

     switch (yes_or_no) { 
      case 'y': 
       puts("Right!");  
       goto done; 

      case 'n': 
       puts("\nhint> Please just say yes for the sake of this demo..."); 
       break; 

      case 'q': 
       puts("\nExitting."); 
       goto done; 

      case EOF: 
       puts("\nEOF."); 
       goto done; 

      default: 
       printf("\nunknown response '%c'.\n", yes_or_no); 
       break; 
     } 
    } 


done: 
    return 0; 
} 

wird:

#include <stdio.h> 
#include <stdlib.h> 
#include <ctype.h> 

static inline void flush_stdin() 
{ 
    char ch; 

    do { 
     ch = getchar(); 
    } while ((ch != '\n') && (ch != EOF)); 
} 

int main(int argc, char **argv) 
{ 
    while (1) { 
     char yes_or_no;   

     printf("is this statement correct? 1 + 1 = 2(Y/N) $ "); 
     yes_or_no = tolower(getchar()); 


     switch (yes_or_no) { 
      case 'y': 
       puts("Right!");  
       goto done; 

      case 'n': 
       puts("hint> Please just say yes for the sake of this demo..."); 
       break; 

      case EOF: 
       puts("EOF."); 
       goto done; 

      default: 
       printf("unknown response '%c'.\n", yes_or_no); 
       break; 
     } 
     flush_stdin(); /* remove this to see the difference */   
    } 


done: 
    return 0; 
} 

Jedes Mal, wenn ich ein einfaches tragbare Konsole Programm machen will, ich fühle mich wie, dass in der Herstellung eine Reihe von Funktionen gezwungen und am Ende habe ich nicht alle Sachen, die ich will, wie getch.

Natürlich können Sie curses verwenden, aber curses übernimmt Ihre gesamte Konsole und bewirkt, dass sich Ihr Programm anders verhält als ein normaler Benutzer (für das Programm nur scrollen und immer noch den Befehl anzeigen, mit dem Sie das Programm ausgeführt haben) der Konsolenpuffer).

Ich weiß "warum" ist eine schlechte Frage (was immer vorzuziehen sein sollte), aber es muss gefragt werden. Gibt es etwas, das in getch nicht inportable ist, dass ein Desktop System nicht unterstützen kann? Wenn nicht, kann ich einfach mein eigenes schreiben und es auf alle Plattformen portieren, die ich unterstützen möchte, und mir geht es gut.

Wenn es etwas getch tut, das nicht von einem Desktop System unterstützt werden kann, was ist das? Also habe ich besseren Grund zu verstehen, warum conio vermieden wird, als "nur ncurses/conio verwenden ist nicht Standard".

+1

Btw, 'ch' sollte vom Typ' int' sein. – pzaenger

+0

Wenn Sie versuchen, formatierte I/O ('scanf' /' printf') und unformatierte I/O ('getchar' /' putchar') zu mischen, brauchen Sie das nicht einmal. – edmz

+0

@pzaenger ich weiß, aber ich machte es char, um zu vermeiden, es mit EOF zu vergleichen, es ungültig machend, weil es die ganzen 4 Bytes anstatt nur 1 Byte vergleichen wird, und eine zusätzliche Besetzung hinzufügend. Es ist ein häufiger Fehler. -black: und dieses Detail ist nicht offensichtlich und verursacht subtile Fehler, die durch benutzerfreundlichere Überlegungen zum Bibliotheksdesign vermieden werden könnten. – Dmitry

Antwort

5

Der C-Standard hat keine Ahnung von Terminals oder Windows. Alles, was zu diesen Dingen gehört, ist implementierungsspezifisch und kann nicht Teil der C-Programmiersprache sein.

Allerdings gibt es Industriestandards für Terminal-Programmierung. Eines ist Teil von POSIX (IEEE 1003.1) als die Terminaltreiberschnittstelle, eines ist X/Open curses, das eine Bibliothek von C-Funktionen spezifiziert, um das Terminal auf einer höheren Ebene zu manipulieren, und das dritte ist ISO 6429, der Satz von ANSI terminale Escape-Sequenzen.

Übrigens bietet X/Open Flüche eine getch() Funktion. Microsoft Windows unterstützt diese Standards auch, aber nicht auf nützliche Weise.

Die Art und Weise Sie getch() unter Windows (dh über conio.h) ist nicht tragbar, obwohl verwenden würde als conio.h ein DOS-spezifischen Header ist, die nicht leicht auf anderen Plattformen implementiert werden kann, aufgrund der unterschiedlichen Modell, wie die Konsole arbeitet in DOS vs. Terminals auf anderen Plattformen.

+0

Ich habe Termini komplett vergessen, ich muss es überprüfen. Danke, dass du mich erinnert hast. – Dmitry

+0

Aber brauchen Sie wirklich eine Vorstellung von Terminal/Fenster, um eaco für ein Zeichen auszuschalten, ein Zeichen zu lesen und es zurückzugeben? Muss der Standard so hoch sein, dass er keine Tastenanschläge erkennt und ausschließlich auf komplette String-Eingänge zugreifen darf? Ist das die einzige Möglichkeit, Dinge tragbar zu machen? – Dmitry

+0

@Dmitry Sie könnten eine neue Frage dazu (es wäre ein bisschen zu sagen) öffnen. Aber, kurz gesagt, die Antwort ist ja, der Standard interessiert sich nicht dafür; §1.2 N1570 _ "Diese Internationale Norm legt nicht fest: [...] den Mechanismus, mit dem Eingabedaten für die Verwendung durch ein C-Programm umgewandelt werden;" _ – edmz