17 Stimmen

Testen, ob stdin Input für C++ hat (Windows und/oder Linux)

Ich möchte im Grunde zu testen, ob stdin Eingabe hat (wie wenn Sie echo und Rohr es). Ich habe Lösungen gefunden, die funktionieren, aber sie sind hässlich, und ich mag meine Lösungen sauber zu sein.

Unter Linux verwende ich dies:

bool StdinOpen() {
  FILE* handle = popen("test -p /dev/stdin", "r");
  return pclose(handle) == 0;
}

Ich weiß, dass ich mehr Fehlerbehandlung hinzufügen sollte, aber das ist nicht der Punkt.

Unter Windows verwende ich dies:

bool StdinOpen() {
  static HANDLE handle = GetStdHandle(STD_INPUT_HANDLE);
  DWORD bytes_left;
  PeekNamedPipe(handle, NULL, 0, NULL, &bytes_left, NULL);
  return bytes_left;
}

Das ist gut für Linux, aber ich möchte wissen, was sind die gleichwertigen APIs, die ich ohne Verwendung einer Pipe aufrufen kann (wie für test -f $file Sie tun fopen($file, "r") != NULL ). Ich habe die Vermutung, dass ich open("/dev/stdin", "r") und dasselbe tun, aber ich möchte wissen, wie ich es am besten anstellen soll.

Zusammenfassung: Ich möchte wissen, welche APIs ich verwenden könnte, um test -p /dev/stdin für Linux, und, falls Sie eine bessere Lösung für Windows kennen.

0 Stimmen

Ihr PeekNamedPipe Lösung schlägt fehl, wenn die Standardeingabe ein Dateihandle (und nicht eine Pipe) ist. Außerdem ist Ihr handle Variable sollte nicht statisch sein. Wenn das Handle umgeleitet wird, während Ihre Anwendung läuft, werden Sie später eine Überraschung erleben.

0 Stimmen

@Billy: Ich glaube nicht, dass ein Handle willkürlich umgeleitet werden kann. Sicher, Sie könnten ändern, was Sie als stdin betrachten, aber das alte Handle ist immer noch da. Aber ich stimme mit dem ersten Teil überein.

0 Stimmen

Lionel B stellt einige Codes für Linux zur Verfügung unter bytes.com/topic/c/answers/841283-wie-erstelle-ich-einen-nicht-blockierenden-aufruf-cin - die Diskussion ist auch lesenswert.

15voto

Antti Punkte 11524

Hier ist eine Lösung für POSIX (Linux): Ich bin nicht sicher, was das Äquivalent von poll() unter Windows ist. Unter Unix ist der Dateideskriptor mit der Nummer 0 die Standardeingabe.

#include <stdio.h>
#include <sys/poll.h>

int main(void)
{
        struct pollfd fds;
        int ret;
        fds.fd = 0; /* this is STDIN */
        fds.events = POLLIN;
        ret = poll(&fds, 1, 0);
        if(ret == 1)
                printf("Yep\n");
        else if(ret == 0)
                printf("No\n");
        else
                printf("Error\n");
        return 0;
}

Prüfung:

$ ./stdin
No
$ echo "foo" | ./stdin
Yep

0 Stimmen

Das ist genau das, was ich wollte. Ich wäre Ihnen ewig dankbar, wenn Sie mir sagen könnten, wie man die Größe des Eingabepuffers misst, aber ich möchte nicht wie ein Fragesteller klingen.

0 Stimmen

Sie können read() verwenden, um die Eingabe zu erhalten. Setzen Sie zunächst den Dateideskriptor 0 mit fcntl() auf nicht-blockierend, dann gibt read() die Anzahl der gelesenen Bytes oder 0 zurück, wenn keine weiteren Daten mehr eingehen.

5 Stimmen

+1. Eine weitere, häufig verwendete Alternative ist select() - konzeptionell ähnliche Verwendung. Es ist wichtig zu beachten, dass diese das Betriebssystem fragen, ob neue Daten aus dem Deskriptor verfügbar sind - wenn Sie auf dieser Ebene arbeiten, müssen Sie eine read() direkt auf den Deskriptor zugreifen, können Sie keine Stdin-Streams auf Bibliotheksebene verwenden oder std::cin (es sei denn, Sie stellen eine neue Pufferimplementierung bereit).

5voto

Matt Parkins Punkte 23056

Würde das nicht funktionieren?

std::cin.rdbuf()->in_avail();

1voto

user541686 Punkte 196656

Ich bin mir nicht sicher, aber ist _kbhit() tun, was Sie brauchen?

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X