10
votes

Comment utiliser SELECT () pour lire l'entrée du clavier en C

J'essaie d'utiliser Select () pour lire l'entrée du clavier et je suis resté coincé dans ce que je ne sais pas comment lire à partir du clavier et utiliser un descripteur de fichier pour le faire. On m'a dit d'utiliser Stdin et Stdin_fileno pour aborder ce problème mais je suis toujours confus.
Comment puis-je le faire?


5 commentaires

C'est une chose assez délicate à faire si vous n'êtes pas familiarisé avec la programmation POSIX en général. Pour une chose, vous devez définir les modes de terminaux afin que l'appareil ne soit pas tampon reçu des caractères.


Pas besoin d'utiliser SELECT (), sauf si bien sûr, cela fait partie d'une tâche des devoirs. Vous pouvez simplement frederder (stdin ...) ou lire (stdin_fileno ...).


Si vous avez besoin de contrôle complet du terminal (appui sur les touches, etc.), vous serez probablement beaucoup mieux d'utiliser une bibliothèque de terminaux tels que NCurses (Il existe également des ports Windows) .


Pete Wilson: Fread (STDIN ...) ne revient pas aussi rapidement que SELECT, si un message arrive sur une prise avant que l'utilisateur ne frappe une touche. Sous Linux, j'ai utilisé Select. Sous Windows, il est plus difficile.


Pouvez-vous s'il vous plaît clarifier pourquoi auriez-vous besoin d'opter pour sélectionner pour lire une entrée de clavier? On sélectionne normalement des appels à lire lorsque vous devez lire à partir d'une gamme de descripteurs ou d'entrées, car il permettra à un programme de surveiller plusieurs descripteurs de fichier, en attente d'un ou plusieurs des descripteurs de fichiers deviennent «prêts» pour une classe d'opérations d'E / S (par exemple, une entrée possible).


3 Réponses :


6
votes

Votre question semble un peu confus. SELECT () code> est utilisé pour bloquer jusqu'à ce que l'entrée soit disponible. Mais vous faites la lecture réelle avec des fonctions de lecture de fichiers normales (comme lisez code>, Fread code>, fgetc. / code>, etc.).

Voici un Exemple rapide. Il bloque jusqu'à ce que STDIN ait au moins un caractère disponible pour la lecture. Mais bien sûr, sauf si vous modifiez le terminal sur un mode non cuit, il bloque jusqu'à ce que vous appuyez sur Entrée, lorsque tous les caractères saisis sont rinçus dans le tampon de fichier (à partir de certains tampons de terminal). P>

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

int main(void) {
    fd_set s_rd, s_wr, s_ex;
    FD_ZERO(&s_rd);
    FD_ZERO(&s_wr);
    FD_ZERO(&s_ex);
    FD_SET(fileno(stdin), &s_rd);
    select(fileno(stdin)+1, &s_rd, &s_wr, &s_ex, NULL);
    return 0;
}


1 commentaires

Merci beaucoup, cela a vraiment clarifié ma question.



1
votes

Peut-être, vous voulez que la façon de jeter l'entrée sur le clavier sur «Windows»? Sous Windows, il ne peut pas obtenir de résultat de SELECT () pour STDIN. Vous devriez utiliser PeekConsoleInput (). Et utilisez la poignée de STDIN comme suit.

hStdin = CreateFile("CONIN$", GENERIC_READ|GENERIC_WRITE, ...


1 commentaires

Windows n'a même pas eu lieu à moi. Nice Save: couvrir tous les angles.



6
votes

Comme on l'a déjà dit, en utilisant Sélectionnez , vous pouvez simplement surveiller E.G. STDIN pour vérifier si les données d'entrée sont déjà disponibles pour la lecture ou non. S'il est disponible, vous pouvez ensuite utiliser par exemple. Fgets Pour lire en toute sécurité les données d'entrée sur un tampon, comme indiqué ci-dessous:

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

int main(int argc, char *argv[])
{
    fd_set rfds;
    struct timeval tv;
    int retval, len;
    char buff[255] = {0};

    /* Watch stdin (fd 0) to see when it has input. */
    FD_ZERO(&rfds);
    FD_SET(0, &rfds);

    /* Wait up to five seconds. */
    tv.tv_sec = 5;
    tv.tv_usec = 0;

    retval = select(1, &rfds, NULL, NULL, &tv);

    if (retval == -1){
        perror("select()");
        exit(EXIT_FAILURE);
    }
    else if (retval){
        /* FD_ISSET(0, &rfds) is true so input is available now. */

        /* Read data from stdin using fgets. */
        fgets(buff, sizeof(buff), stdin);

        /* Remove trailing newline character from the input buffer if needed. */
        len = strlen(buff) - 1;
        if (buff[len] == '\n')
            buff[len] = '\0';

        printf("'%s' was read from stdin.\n", buff);
    }
    else
        printf("No data within five seconds.\n");            

    exit(EXIT_SUCCESS);
}


0 commentaires