Debian logo [embedded-µC.LINUX]

8. Entrées et sorties standard : fonctions getchar & putchar

8.1. Avec Système d'exploitation

Entrée standard, Fonction getchar, Flux stdin

Le mécanisme d'entrée le plus simple consiste à lire un caractère provenant de l'entrée standard. Suivant le contexte, cette entrée standard peut prendre différente formes.

Sur un ordinateur, les caractères sont généralement lus à partir d'un clavier. Ils peuvent cependant provenir de différents «canaux» : fichiers, redirections de flux ou opérations de séquencement entre les programmes de la couche Shell (pipes ou tubes).

Sur un système embarqué les caractères peuvent provenir des même canaux. Sans système d'exploitation, la liste des canaux est limitée aux interfaces disponibles. Dans les exemples présentés dans ce document, c'est la liaison série qui sert le plus souvent de flux d'entrée standard.

Par principe, la fonction getchar transmet au programme appelant le caractère suivant de la file d'entrée à chaque appel.

Sortie standard, Fonction putchar, Flux stdout

Par analogie avec le cas de l'entrée standard, le mécanisme le plus simple consiste à émettre un caractère vers la sortie standard. Suivant le contexte cette sortie standard peut aussi prendre différentes formes.

Sur un ordinateur, les caractères sont émis par défaut vers le terminal (ie. la fenêtre du Shell courant). Comme pour toute manipulation au niveau Shell, les opérations de séquencement, de redirection et les tubes sont utilisables. Voir les exemples d'exécution ci-après.

Ces mécanismes d'entrées-sorties standard ont été définis avec les systèmes d'exploitation UNIX au début des années 70. On les retrouve aujourd'hui sur la totalité des systèmes d'exploitation contemporains. Les files d'attentes des caractères issus de l'écran, du clavier, des fichiers stockés sur tous types de supports, etc. sont appelés flux d'entrées-sorties (input-output streams). Des flux standards ont été définis ; chacun étant dédié à un «pseudo-périphérique».

  • stdin : flux d'entrée ; généralement le clavier,

  • stdout : flux de sortie ; généralement l'écran,

  • stderr : flux d'erreurs vers lequel sont redirigés tous les messages d'erreurs lors de l'exécution d'un programme,

  • stdprn : flux d'impression ; généralement le port parallèle,

  • stdaux : flux auxiliaire ; généralement le port série.

Voici un exemple simple de programme utilisant les flux d'entrées-sorties standard via les fonctions getchar et putchar. Ce programme recopie les caractères reçus sur le flux d'entrée stdin vers le flux de sortie stdout. Cette copie se poursuit tant que le caractère saisi est différent du code ASCII de délimitation de fin de fichier EOF (code obtenu en appuyant simultanément sur les touches Ctrl + D).

Exemple 9. Utilisation des fonctions getchar & putchar avec GCC

01: #include <stdio.h>
02: 
03: int main() {
04: 
05:    char c;
06: 
07:    while ((c = getchar()) != EOF)
08:       putchar(c);
09:    
10:    return 0;
11: }

L'exemple d'exécution du programme ci-dessous montre que l'opération de transfert d'un flux vers l'autre est séquencée par le caractère de saut de ligne \n. Le flux d'entrée se «remplit» tant qu'aucun appui sur la touche Entrée n'intervient. Dès que le code ASCII du saut de ligne entre dans le flux d'entrée standard, son contenu est transféré au programme utilisateur via l'appel à la fonction getchar.

Les appels à la fonction putchar suivent le même fonctionnement vis-à-vis du flux de sortie standard.

Voici un exemple d'exécution du programme gcc_stdio.c :

$ ./gcc_stdio.out
test
test
123
123

Voici deux autres exemples d'exécution du même programme en utilisant les opérations de séquencement entre les programmes offertes par le Shell.

  • On commence par créer un fichier test.txt à l'aide de la commande cat. Tous les caractères saisis au clavier sont redirigés vers le fichier. L'opération s'arrête avec la saisie du code ASCII EOF (Ctrl + D).

  • Le programme est exécuté avec une nouvelle redirection : ./stdio <test.txt. Avec cette redirection, le contenu du fichier test.txt se substitue au flux d'entrée standard stdin.

  • Le programme est à nouveau exécuté en utilisant un tube (pipe). En fait, deux programmes sont exécutés : cat test.txt et stdio. Le premier à pour but d'afficher le contenu du fichier texte sur le flux de sortie standard stdout (ie. la console). Le fonctionnement du second programme a déjà été décrit ci-dessus. L'utilisation du tube permet de transférer la sortie du premier programme vers l'entrée du second.

phil@b0x:~/src$ cat >test.txt
Fichier texte
exemple
phil@b0x:~/src$ ./stdio <test.txt
Fichier texte
exemple
phil@b0x:~/src$ cat test.txt | ./stdio
Fichier texte
exemple

Pour plus de détails sur les manipulations à la console, voir Linux - Base d'administration pour le superutilisateur.

8.2. Sans système d'exploitation & cible MSC1210

Voici maintenant le même exemple simple de programme utilisant les flux d'entrées-sorties standard sur un système spécialisé. Dans ce contexte sans système d'exploitation, on ne dispose pas de définition des flux stdin et stdout entre le noyau et le Shell. On continue cependant à utiliser les fonctions getchar et putchar.

La technique usuelle sur les systèmes spécialisés consiste à donner une nouvelle définition de ces deux fonctions en désignant explicitement le canal de réception et d'émission des caractères. Dans l'exemple, c'est la liaison série entre le PC de développement et le système spécialisé qui sert à faire transiter les caractères dans les deux sens.

Exemple 10. Utilisation des fonctions getchar & putchar sur microcontrôleur MSC120 avec SDCC

01: #include <stdio.h>
02: #include <msc1210.h>
03: #include "ser_msc1210.h"
04: 
05: #define EOF 0x04
06: #define CR  0x0d
07: 
08: char getchar(void) {
09:   return ser_getc();
10: }
11: 
12: void putchar(char c) {
13:   ser_putc(c);
14: }
15: 
16: void main(void) {
17: 
18:    char c;
19: 
20:    // Press <Enter> for auto baudrate adjust
21:    autobaud();
22:    EA=1;
23: 
24:    while ((c = getchar()) != EOF) {
25:       if (c == CR)
26:          putcr();
27:       putchar(c);
28:    }
29:    putcr();
30:    putchar('!');
31:    putcr();
32: 
33:    while (1);
34: }

Comme on l'a déjà indiqué, il n'existe pas de couche Shell dans ce contexte. On ne dispose donc pas d'opération de séquencement entre programmes puisque cet exemple est le seul programme exécuté par le microcontrôleur.

Voici un exemple d'exécution du programme sdcc_stdio.c :

MSC1210 Ver:000305F10
>M0000 ok
>M8000 ok
>E
>T
>
>azerty
123

!