Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

comprendre getchar()

59 réponses
Avatar
bpascal123
Je trouve getchar() assez difficile =E0 comprendre. Au lieu de saisir du
clavier, getchar lit directement dans la m=E9moire? Presser une touche
du claver entraine un signal dans le bios qui "renvoie" ce signal dans
le kernel puis dans la m=E9moire (buffer) et de ce dernier est affich=E9
le caract=E8re de la touche press=E9e (par ex.: a) pr=E9c=E9demment. Par
contre le caract=E8re reste toujours dans le buffer mais dans la partie
"ancienne" du buffer. Dans la partie "neuve", se trouverait les
caract=E8res qui n'ont pas =E9t=E9 affich=E9s =E0 l'=E9cran ou trait=E9s d'=
une autre
mani=E8re.

Ce code d'apparence simple pour la saisie me laisse perplexe:

#include <stdio.h>

int main(void)
{
char c ;
c =3D getchar() ;

while ( c !=3D EOF )
{
putchar(c) ;
c =3D getchar() ;
}
return 0 ;
}

Je me demande si un petit apprentissage de l'assembleur jusqu'=E0
comprendre ce code, ne serait pas utile dans ce cas?

10 réponses

1 2 3 4 5
Avatar
Vivien Moreau
On 2010-06-19, wrote:

#include <stdio.h>

int main(void)
{
char c ;
c = getchar() ;

while ( c != EOF )
{
putchar(c) ;
c = getchar() ;
}
return 0 ;
}



Attention, contrairement à ce que l'on pourrait penser,
getchar() renvoit un entier; voir son prototype :
int getchar(void);

C'est simplement parce que EOF a une valeur qui par
définition ne peut être de type char.

--
Vivien Moreau
Avatar
Benoit Izac
Bonjour,

le 19/06/2010 à 02:14, bpascal a écrit dans le message
:

Je trouve getchar() assez difficile à comprendre. Au lieu de saisir du
clavier, getchar lit directement dans la mémoire? Presser une touche
du claver entraine un signal dans le bios qui "renvoie" ce signal dans
le kernel puis dans la mémoire (buffer) et de ce dernier est affiché
le caractère de la touche pressée (par ex.: a) précédemment. Par
contre le caractère reste toujours dans le buffer mais dans la partie
"ancienne" du buffer. Dans la partie "neuve", se trouverait les
caractères qui n'ont pas été affichés à l'écran ou traités d'une autre
manière.

Ce code d'apparence simple pour la saisie me laisse perplexe:

#include <stdio.h>

int main(void)
{
char c ;



Attention, getchar() renvoie un int !

c = getchar() ;

while ( c != EOF )
{
putchar(c) ;
c = getchar() ;
}
return 0 ;
}

Je me demande si un petit apprentissage de l'assembleur jusqu'à
comprendre ce code, ne serait pas utile dans ce cas?



Non, tu te poses vraiment trop de questions, il n'y a aucune histoire de
buffer ici. Tu lis un caractère dans stdin, puis tant que ce caractère
n'est pas EOF (fin de fichier), tu l'envoies sur stdout puis tu en lis
un autre, etc. Il n'y a pas à aller chercher plus loin.

--
Benoit Izac
Avatar
xtof pernod
Le 19/06/2010 09:37, Benoit Izac a %écrire :
le 19/06/2010 à 02:14, bpascal a écrit dans le message
:
(...)
Ce code d'apparence simple pour la saisie me laisse perplexe:

#include<stdio.h>

int main(void)
{
char c ;



Attention, getchar() renvoie un int !




Ultra-classique, comme 'bug' / piège / etc..
Si tu es tombé dessus, c'est un signe que tu es sur La Voie ;)

{...}

Je me demande si un petit apprentissage de l'assembleur jusqu'à
comprendre ce code, ne serait pas utile dans ce cas?



Non, tu te poses vraiment trop de questions, il n'y a aucune histoire de



nb_Non++;

buffer ici. Tu lis un caractère dans stdin, puis tant que ce caractère


^^^^^^ ^^^^^
sisi, c'est le but de stdio d'ailleurs.

n'est pas EOF (fin de fichier), tu l'envoies sur stdout puis tu en lis
un autre, etc. Il n'y a pas à aller chercher plus loin.



Peut-être dans une bonne doc', genre le K&R ? au chapitre quivabien(c;)

>> c = getchar() ;



--
christophe.
Avatar
Samuel DEVULDER
a écrit :
Je trouve getchar() assez difficile à comprendre.



Non c'est tout con: il te retourne le dernier caractère lu au clavier ou
EOF. C'est tout. Après on on se fiche de savoir comment ca marche en
dessous pour pouvoir l'utiliser.

Ce code d'apparence simple pour la saisie me laisse perplexe:



Pourquoi? A part le pb de type du retour de getchar(), ce code est tout
bête. Aucune astuce rien. C'est du tout simple, qu'on trouve dans tous
les langages e programmation, sur toutes les machines.

Je me demande si un petit apprentissage de l'assembleur jusqu'à
comprendre ce code, ne serait pas utile dans ce cas?



L'assembleur n'a rien à voir avec ce que fait ce code. Tu ne comprendras
pas mieux ce code en assembleur qu'en C ou en Pascal.

Tu te poses trop de questions, ca te dispersse et ca nuit à ta progression.

sam.
Avatar
Benoit Izac
Bonjour,

le 19/06/2010 à 09:57, xtof pernod a écrit dans le message
<4c1c785c$0$27587$ :

[ c = getchar(); ]

Je me demande si un petit apprentissage de l'assembleur jusqu'à
comprendre ce code, ne serait pas utile dans ce cas?



Non, tu te poses vraiment trop de questions, il n'y a aucune histoire de



nb_Non++;

buffer ici. Tu lis un caractère dans stdin, puis tant que ce caractère


^^^^^^ ^^^^^
sisi, c'est le but de stdio d'ailleurs.



Maintenant que tu as commencé, il va falloir que tu développes ta pensée
jusqu'au bout car je ne vois où tu veux en venir.

--
Benoit Izac
Avatar
espie
In article ,
wrote:
Je trouve getchar() assez difficile à comprendre. Au lieu de saisir du
clavier, getchar lit directement dans la mémoire? Presser une touche



Non, en fait les problemes que tu te poses sont beaucoup, beaucoup, plus
haut en terme de design.

C a ete concu en meme temps qu'un OS, typiquement Unix/Linux, et le
fonctionnement de getchar() est guide par les contraintes d'un systeme
d'exploitation.

Un systeme d'exploitation est cense t'isoler du materiel. Il va te fournir
des primitives (dites aussi appels systemes) qui sont censees te permettre
d'interagir avec la machine. Prenons le cas du clavier. Tu vas disposer
d'un appel systeme, disons read(), qui doit te permettre de recuperer des
informations depuis ce clavier. Il y a des choix a faire lors du design du
systeme: est-ce qu'on va te donner uniquement des infos du clavier, ou
est-ce que read() est une primitive d'entree plus generale (sous Unix, c'est
une primitive d'entree generale: initialement clavier du teletype, puis
console de type VT connectee sur un port serie, puis clavier reel, et enfin
connexion reseau par ssh. Tout ceci a ete supporte a l'identique sans
changement du code utilisateur. C'est tout l'interet d'un OS: t'isoler de
la couche materielle, de facon a te permettre de ne pas changer ton code
en permanence.

Par exemple, aujourd'hui, le code de la libc d'un Unix est pour
l'immense majorite independant du materiel: tant qu'il y a un read() qui
fonctionne, stdio va s'en servir, et getchar() fonctionnera.


Petit probleme de performances: sur un systeme d'exploitation decent, un
appel systeme n'est PAS un appel de fonction standard. Typiquement il prend
plus de temps. La raison est toute bete: tu n'es pas forcement tout seul
sur la machine, tu n'as donc acces qu'a ton "terrain de jeu" et pas du tout
au materiel. Les appels systemes sont un mecanisme d'echappement (des traps,
interruptions, enfin bref, le mecanisme materiel propre a ton processeur)
qui te permettent de demander un service a ton OS, qui lui a acces au
materiel (et qui arbitre entre les divers utilisateurs, par exemple qui sait
si tu es cense avoir acces au clavier). Du coup, appeler read() pour CHAQUE
caractere coute tres cher (on considere qu'un appel systeme est d'un a deux
ordres de grandeur plus lent qu'un appel de fonction standard). Et donc
on bufferise: l'OS lit plein de caracteres du clavier, et les renvoie a
la bibliotheque standard en une seule fois, et celle-ci les stocke dans
un tampon associe a stdin, et te les passe au goutte-a-goutte, jusqu'a
ce que le tampon soit vide (et la, on rappelle read()... jusqu'a tomber sur
EOF).

La-aussi, choix de design: combien de caracteres a chaque fois ? Si on en
recupere plein, on appelera read() moins de fois, et ca ira plus vite !
Mais bon, pour des entrees-sorties a l'affichage, et pas sur un fichier,
c'est pas tip-top cote interaction avec l'utilisateur.

Du coup, la bibliotheque standard adapte ses strategies de gestion de tampon
au fichier concerne. Tu as trois strategies differentes, toutes utilisee.
stdin/stdout: ligne par ligne
stderr: pas de tampon, sortie transparente
autre fichier: gros tampon

Ainsi, par defaut, lorsque tu appelles getchar(), l'OS va recuperer une
ligne entiere depuis le clavier, et te la fournir caractere par caractere.
De meme, lorsque tu appelles putchar(), celui-ci ne va rien afficher, juste
stocker des caracteres jusqu'a avoir une ligne entiere.


Autre avantage a bufferiser des lignes entieres en entree: ca permet a l'OS
de gerer des touches speciales du clavier, que normalement tu ne vois jamais,
telles que tes fleches, ou ton delete. (j'y reviens pljus tard).

Ceci se modifie plus ou moins, deja au niveau de la bibliotheque standard:
- cote tampons des flux, la fonction setvbuf() te permet de changer de
strategie.
- cote sortie, la fonction fflush() te permet de provoquer un affichage
immediat.

Cote entree, c'est plus complique: il n'y a pas d'equivalent de fflush()
portable. En particulier, la gestion des touches speciales se fait
dans l'OS lui-meme. Sur un Unix, c'est du ressort d'un module special
du noyau associe a ton terminal, dit tty. Et il y a des fonctions decrites
dans termios (tcgetattr/tcsetattr) qui permettent de manipuler ce terminal.
C'est tres casse-gueule a utiliser, entre autres a cause des signaux de
job control, et la plupart des gens n'y touchent jamais, et passent par
des bibliotheques telles que curses pour faire les choses.
Avatar
bpascal123
Je laisse la parole à Marc: --> <hvi0lp$

--
christophe.



Je comprends que getchar() renvoie un entier. J'avais vu quelque part
qu'en déclarant char c = getchar() et plus loin indiquer
printf("%d",c) on pouvait voir la valeur de EOF...

Par hasard, ce code ne fonctionne pas sous linux distro ubuntu...
(j'essaie de m'intéresser à ce qui se passe "sous le rideau", la
réponse précédente (Marc E.) est intéressante pour ça. Cdt.

#include <stdio.h>
#include <bios.h>

main()
{
unsigned int saisie;
int carlu, scancode;
printf ("Press a key:n");
saisie = _bios_keybrd(_KEYBRD_READ);
carlu = saisie & 255;
scancode = saisie >> 8;
printf("nScancode : %d Caractere : %cn", scancode, carlu);
}
Avatar
espie
In article ,
wrote:

Je laisse la parole à Marc: --> <hvi0lp$

--
christophe.



Je comprends que getchar() renvoie un entier. J'avais vu quelque part
qu'en déclarant char c = getchar() et plus loin indiquer
printf("%d",c) on pouvait voir la valeur de EOF...




Je ne sais pas ou tu as lu ca, mais c'est a proscrire. C'est quelqu'un
qui ne comprend RIEN au C qui a ecrit ca. -> brule le site entier (ou le
bouquin) dont c'est issu.

Le C ne supporte PAS l'approximation ! Si tu apprends sur des trucs faux,
c'est pas etonnant que tu aies les idees confuses.

-> toujours stocker le resultat de getchar() dans un int. C'est seulement
APRES avoir fait un test pour s'assurer que c'est != EOF que tu peux
prendre le resultat et le mettre dans un char.

-> si tu stockes la valeur de getchar() dans un char, tu n'auras PAS la
valeur d'EOF, mais ce que donne la valeur d'EOF convertie en char (et donc
avec perte de precision possible).

-> in fine, la valeur d'EOF n'a *aucune espece d'importance*. Tout ce qu'on
lui demande, c'est:
- de rentrer dans un entier int;
- d'etre distincte de toutes les autres valeurs renvoyable par getchar() et
assimile...
Avatar
xtof pernod
Le 20/06/2010 20:53, a fait rien qu'à écrire:
Par hasard, ce code ne fonctionne pas sous linux distro ubuntu...



En effet, il est prévu pour MS-DOS.. aucune chance que ça passe --
même pas à la compil'. Pas de hasard là-dedans =)

(j'essaie de m'intéresser à ce qui se passe "sous le rideau", la
réponse précédente (Marc E.) est intéressante pour ça. Cdt.



Bon, Marc.. Tu as un double appel.

#include <stdio.h>
#include <bios.h>


^^^^^^^^
main()
{
unsigned int saisie;
int carlu, scancode;
printf ("Press a key:n");
saisie = _bios_keybrd(_KEYBRD_READ); // <- Hum. accès au bios en mode réel/16 bits
carlu = saisie & 255;
scancode = saisie >> 8;,
printf("nScancode : %d Caractere : %cn", scancode, carlu);
}



Je peux pas nier, c'est rafraîchissant & ça rappelle des vieux
souvenirs.. Tu l'as taupé dans quoi, franchement, dans "la Bible
de la progra. sous DOS" ?

Mais le fait est, tu mets de la verveine de 20 ans d'âge dans ta
limousine de l'année, et tu viens dire "-comprends pas, ça démarre
même pas"..

Si tu as internet, tu devrais pouvoir dégotter des examples plus récents
(et plus adaptés à Linux. Au moins du C standard)

--
christophe.
Avatar
Benoit Izac
Bonjour,

le 20/06/2010 à 20:53, bpascal a écrit dans le message
:

Je comprends que getchar() renvoie un entier. J'avais vu quelque part
qu'en déclarant char c = getchar() et plus loin indiquer
printf("%d",c) on pouvait voir la valeur de EOF...



On s'en fout de sa valeur. Sur tout les systèmes elle vaut « EOF »,
c'est la seule chose qu'il faut retenir.

Par hasard, ce code ne fonctionne pas sous linux distro ubuntu...
(j'essaie de m'intéresser à ce qui se passe "sous le rideau", la
réponse précédente (Marc E.) est intéressante pour ça. Cdt.

#include <stdio.h>
#include <bios.h>

main()
{
unsigned int saisie;
int carlu, scancode;
printf ("Press a key:n");
saisie = _bios_keybrd(_KEYBRD_READ);
carlu = saisie & 255;
scancode = saisie >> 8;
printf("nScancode : %d Caractere : %cn", scancode, carlu);
}



Tu t'éparpilles. Pourquoi cherches-tu à brûler les étapes ?

Tu devrais prendre le K&R, le lire chapitre par chapitre et faire les
exercices un par un. On peut dire ce que l'on veut à propos de ce livre,
je pense qu'il est assez bien fait : il avance sur les concepts propres
au langage assez linéairement. Ce qui a été pour ma part le plus délicat
concerne plus des problèmes de logique que mon cerveau n'était pas
habitué à utiliser mais qui sont indispensables en programmation.

Si tu as un problème pour comprendre un passage ou pour résoudre un
exercice, les intervenants de ce groupe se feront une joie de
t'éclaircir. Énonce clairement (c'est un de tes points faibles) ton
problème et tu verras que bien souvent juste le fait de réfléchir pour
rédiger ton message t'aidera à te poser les bonnes questions.

Une fois que tu auras fini ce livre (attention, ça risque déjà de te
prendre un certain temps malgré qu'il n'y ai que 182 pages de cours dans
la version française), tu verras que tu te poseras beaucoup moins de
questions, que tu pourras faire déjà pas mal de choses et tu sauras où
chercher pour utiliser des fonctions propres à ton système.

<élucubration>
Par la suite, il te prendra sans soute l'envie d'approfondir le langage
en lisant la norme ; tu pourras déjà venir troller^Wdiscuter ici des
points de détails que tu auras découverts. Tu t'apercevras d'ailleurs
que bien que tout le monde ai lu la même chose, chacun l'interprète
différemment.

Ensuite, tu chercheras à en savoir plus, tu t'attaqueras à un livre un
peu plus conséquent. Comme tu hésiteras à approfondir tes connaissances
en programmation système ou en algorithmique, tu t'attaqueras à Steven
et Knuth. Ça te demandera encore quelques années pour les assimiler.

À ce moment là, tu t'apercevra que tu ne sauras toujours pas capable
d'écrire ton pilote pour ton périphérique qui aura disparu du marché et
que tu ne souhaiteras plus utiliser. Tu liras LDD édition 7 qui te
permettra de combler tes lacunes. Et enfin tu te mettra à l'assembleur.

Au final, tu pourras te présenter sur le marché du travail. La gentille
personne au guichet essaiera de t'expliquer avec tact qu'à ton âge et
avec ton expérience professionnelle, il te sera vraiment très difficile
de trouver un emploi à quelques années de la retraite. Enfin tu
réaliseras (sans doute un peu trop tard) qu'au fond la comptabilité
c'était pas si mal.
</élucubration>

--
Benoit Izac
1 2 3 4 5