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

N'arrive pas afficher "b" en sortie pour chaque "retour en arrière" en entrée

8 réponses
Avatar
Francois
Bonjour à tous,

Je n'arrive pas à résoudre l'exercice 1-10 du K&R2 (chapitre 1-5-3).
Voici l'énoncé : le programme doit copier son entrée sur sa sortie en
remplaçant les tabulations par \t, les retours en arrière par \b et les
backslashs par \\.

Voici mon code :

/*--------------------------------------*/
#include <stdio.h>


int main( void )
{
int c ;

while ( (c = getchar()) != EOF)
{
if ( c == '\t' )
{
printf("\\t") ;
}

if ( c == '\b' )
{
printf("\\b") ;
}

if ( c == '\\' )
{
printf("\\\\") ;
}

if ( c != '\t' & c!= '\b' & c!= '\\')
{
putchar(c) ;
}
}

printf("\n\nC'est fini, merci !\n\n") ;

return 0 ;
}
/*--------------------------------------*/

Quand je lance le programme et que je tape :
- sur la touche "1"
- puis sur la touche "2"
- puis sur la touche "retour en arrière"
- puis sur la touche "ENTER"

Je m'attends à ce que s'affiche : 12\b. Mais en fait, seul "1" s'affiche.

Je ne comprends pas pourquoi \b n'est pas apparu. Avez-vous une
explication à me donner ? Comment corriger le code ?


Merci d'avance.


François

8 réponses

Avatar
Jean-Marc Bourguet
Francois writes:

Quand je lance le programme et que je tape :
- sur la touche "1"
- puis sur la touche "2"
- puis sur la touche "retour en arrière"
- puis sur la touche "ENTER"

Je m'attends à ce que s'affiche : 12b. Mais en fait, seul "1" s'affiche.

Je ne comprends pas pourquoi b n'est pas apparu. Avez-vous une explication
à me donner ?


Le plus probable est que le retour en arriere soit gere par le driver de
terminal (ou ou le terminal lui-meme si tu es reellement dans une
configuration digne de K&R1 :-)) et donc que ton code ne le voit jamais.

Comment corriger le code ?


Je ne crois pas qu'il soit a corriger, meme si je ne l'aurais pas ecrit
ainsi. (J'aurais utilise un switch ou des else -- et donc pas de condition
redondante difficile a maintenir).

--
Jean-Marc
FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
Jean-Marc Bourguet
Jean-Marc Bourguet writes:

Francois writes:

Quand je lance le programme et que je tape :
- sur la touche "1"
- puis sur la touche "2"
- puis sur la touche "retour en arrière"
- puis sur la touche "ENTER"

Je m'attends à ce que s'affiche : 12b. Mais en fait, seul "1" s'affiche.

Je ne comprends pas pourquoi b n'est pas apparu. Avez-vous une explication
à me donner ?


Le plus probable est que le retour en arriere soit gere par le driver de
terminal (ou ou le terminal lui-meme si tu es reellement dans une
configuration digne de K&R1 :-)) et donc que ton code ne le voit jamais.

Comment corriger le code ?


Je ne crois pas qu'il soit a corriger, meme si je ne l'aurais pas ecrit
ainsi. (J'aurais utilise un switch ou des else -- et donc pas de condition
redondante difficile a maintenir).


J'oubliais: - il n'est pas sur que le retour en arriere envoie un b, chez
moi ca envoie un DEL. Utilise donc plutot CTRL-H meme si il est probable
que ma premiere explication soit la bonne.

- pour tester ton code, il faut soit mettre le driver de terminal dans un
mode ou il ne tente pas de traiter ce caractere... sans pour autant
empecher de notifier la fin de fichier. Je n'ai aucune idee de comment
faire sous Windows, sous Unix stty sert a gerer cela.

stty erase ^@

devrait desactiver la gestion du BS.

A+

--
Jean-Marc
FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc
Site de usenet-fr: http://www.usenet-fr.news.eu.org


Avatar
Francois
Merci pour les réponses. Au fait, je suis sur Ubuntu.

J'oubliais: - il n'est pas sur que le retour en arriere envoie un b, chez
moi ca envoie un DEL. Utilise donc plutot CTRL-H meme si il est probable
que ma premiere explication soit la bonne.


Alors effectivement, j'arrive à faire apparaître les caractères "" et
"b" en sortie grâce à CTRL-H lorsque quand je tape sur :

- A
- B
- CTRL-H
- puis enfin sur ENTER

Dans ce cas j'ai bien en sortie ABb. Mais par contre, le truc bizarre,
c'est qu'au moment où je tape la suite de touche énumérée ci-dessus,
l'écran m'affiche "AB^H" et non comme j'imaginais "A" où le B aurait été
effacé par le CTRL-H. Autrement dit, le CRTL-H ne remplit pas la
fonction de "retour en arrière" (celle qui efface la lettre avant le
curseur).

- pour tester ton code, il faut soit mettre le driver de terminal dans un
mode ou il ne tente pas de traiter ce caractere... sans pour autant
empecher de notifier la fin de fichier. Je n'ai aucune idee de comment
faire sous Windows, sous Unix stty sert a gerer cela.

stty erase ^@

devrait desactiver la gestion du BS.



Quand je fais ça, lorsque j'appuie sur la touche "retour en arrière" sur
l'écran il s'affiche "^?", sans que le caractère juste avant le curseur
ne soit effacé. De plus avec le programme, si je tape :

- sur A
- puis sur la touche "retour en arrière"
- puis enfin sur ENTER (tout cela va m'afficher "A^?")

j'ai en sortie simplement "A", pas de b.


Tout ça pour dire que, pour l'instant, le seul moyen que j'ai pu trouver
pour afficher "b" en sortie avec le programme, c'est de taper CTRL-H
qui ne remplit pas la fonction de retour en arrière mais qui affiche "^H" ?

Je ne suis pas sûr de bien comprendre par rapport à mon terminal. Vous
voulez dire que la touche retour en arrière est "particulière" pour mon
terminal dans le sens où il n'envoie pas le caractère retour en arrière
en sortie, par contre il efface bien le caractère précédent, si bien que
dans le flux de sortie nulle trace du caractères retour en arrière.
C'est bien cela ?

De toute façon, mon terminal il a toujours eu des comportement bizarre.
Par exemple, pas de CTRL-C CTRL-V possible. Le CTRL-V m'affiche aussi "^V).


PS : au fait, dans mon code initial, j'ai l'impression qu'il y a une
erreur. C'est "&&" qu'il faut mettre au lieu de "&". Pourtant le
compilateur n'avait rien dit ?

Avatar
Jean-Marc Bourguet
Francois writes:

PS : au fait, dans mon code initial, j'ai l'impression qu'il y a une
erreur. C'est "&&" qu'il faut mettre au lieu de "&". Pourtant le
compilateur n'avait rien dit ?


Tu auras une reponse pour le reste quand j'aurais le temps de l'ecrire.

J'avais vu ca et j'ai oublie de commente dessus car ce n'est pas lie au
probleme.

& effectue un "et binaire", cad sur chaque bit de la representation des
nombres (entiers) que tu combines.

&& effectue un "et logique", cad qu'il retourne 0 uniquement si les deux
nombres sont 0.

Comme tu ne passais que des 0 et des 1 (le resultat des operateurs de
comparaison est garanti etre 0 ou 1), ca ne change pas grand chose dans ton
cas.

A+

--
Jean-Marc
FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
Francois
Francois writes:

PS : au fait, dans mon code initial, j'ai l'impression qu'il y a une
erreur. C'est "&&" qu'il faut mettre au lieu de "&". Pourtant le
compilateur n'avait rien dit ?


Tu auras une reponse pour le reste quand j'aurais le temps de l'ecrire.


Pas de problème, je comprends Ô combien ce genre d'argument. ;-)

Comme tu ne passais que des 0 et des 1 (le resultat des operateurs de
comparaison est garanti etre 0 ou 1), ca ne change pas grand chose dans ton
cas.


Ok, c'est parfaitement clair sur ce point. Merci.


François


Avatar
Antoine Leca
En news:47da6ba0$0$11225$, Francois va escriure:
Alors effectivement, j'arrive à faire apparaître les caractères "" et
"b" en sortie grâce à CTRL-H lorsque quand je tape sur :

- A
- B
- CTRL-H
- puis enfin sur ENTER

Dans ce cas j'ai bien en sortie ABb.


Oui (à partir du moment où la fonction de b est remplie par le caractère de
code Ctrl-H sur ta machine, ce qui est la manière normale et habituelle).

Mais par contre, le truc
bizarre, c'est qu'au moment où je tape la suite de touche énumérée
ci-dessus, l'écran m'affiche "AB^H" et non comme j'imaginais "A" où
le B aurait été effacé par le CTRL-H. Autrement dit, le CRTL-H ne
remplit pas la fonction de "retour en arrière" (celle qui efface
la lettre avant le curseur).


Voilà. Note cependant que ceci est le comportement de ta machine, en
particulier du programme que tu utilises comme « terminal » (probablement un
avatar de xterm) sur ton système (Ubuntu, tel qu'il est configuré chez moi).

Ce que je veux dire, c'est que ce comportement que tu observes est en dehors
du domaine d'action du langage C : ici la norme se borne à dire que
l'émission de ce caractère 'b' via *putc() est sensée déplacer le «
curseur » sur le caractère précédent ; et ne précise rien sur le
comportement en entrée [fonctions *getc()] ; ce qui est tu l'avoueras
extrêmement réduit.
En fonction des caractéristiques de ton compilateur (gcc+glibc pour toi, et
peut-être aussi des normes Posix ou X/Open propres à ton environnement) tu
pourrais avoir plus de garanties dans un sens ou un autre, mais là je suis
incapable de savoir te renseigner plus, désolé.


Quand je fais ça, lorsque j'appuie sur la touche "retour en arrière"
sur l'écran il s'affiche "^?",


^? est la manière la plus habituelle pour un pilote de terminal (au sens
ci-dessus) de représenter le caractère DEL, dont le code est 127. Autrement
dit, ton terminal considère que la touche retour arrière est liée au
caractère 127, pas au caractère b (qui a le code 8 pour ton
implémentation).

Les implémentations n'ont pas toutes le même comportement. Par exemple, sur
la machine où je tape ceci, la touche retour arrière génère un code 8, et si
j'appuie sur Ctrl en même temps j'ai un caractère 127 (il s'agit ici du
standard IBM PC). Ce genre de truc est paramétrable au niveau du programme
de gestion du terminal, man stty va te montrer jusqu'à quel point on peut
pousser la perversité dans ce domaine ; en particulier, stty erase peut
éventuellement avoir un effet dans le sens que tu veux ; ou pas.


Tout ça pour dire que, pour l'instant, le seul moyen que j'ai pu
trouver pour afficher "b" en sortie avec le programme, c'est de
taper CTRL-H qui ne remplit pas la fonction de retour en arrière
mais qui affiche "^H" ?


Voilà. J'ai tendance à penser qu'il y a comme un défaut au niveau de la
conformité à la norme avec ta configuration, mais
1) ce n'est pas grave
2) je n'en suis pas sûr
3) sachant que ta configuration est (probablement) un standard Unix, je
doute qu'il soit possible d'y remédier autrement qu'au niveau local en
changeant les paramètres de ta configuration.


Je ne suis pas sûr de bien comprendre par rapport à mon terminal. Vous
voulez dire que la touche retour en arrière est "particulière" pour
mon terminal dans le sens où il n'envoie pas le caractère retour en
arrière en sortie, par contre il efface bien le caractère précédent,


Voilà. Note bien que « retour en arrière » (ou « déplacement à gauche » pour
nous autres qui écrivons de gauche à droite) est une fonction différente de
« effacement du dernier caractère », même si les terminaux à écran auxquels
nous sommes tant habitués cela semble similaire.


si bien que dans le flux de sortie nulle trace du caractères retour
en arrière. C'est bien cela ?


Euh pas tout-à-fait sûr, il y a un truc en plus qui s'appelle « la gestion
de la ligne d'entrée » (line handling, cooked/raw mode) qui interfère. Mais
c'est passablement hors sujet pour ce forum, et en plus je en suis pas
capable de t'expliquer cela en quelques lignes, il est probablement beuacoup
plus facile que tu explores Internet si ce sujet te passionnes.



Antoine

Avatar
Francois
Ce que je veux dire, c'est que ce comportement que tu observes est en dehors
du domaine d'action du langage C


Oui, c'est cela concerne le comportement du terminal de mon ordinateur,
pas le C. Nous sommes d'accord.

ici la norme se borne à dire que
l'émission de ce caractère 'b' via *putc() est sensée déplacer le «
curseur » sur le caractère précédent ; et ne précise rien sur le
comportement en entrée [fonctions *getc()] ; ce qui est tu l'avoueras
extrêmement réduit.


Oui, je trouve. Chez moi, par contre en sortie, il n'y a pas photo. Ceci :

putchar('1') ;
putchar('2') ;
putchar('3') ;
putchar('b') ;

m'affiche "12" en sortie. Donc, non seulement le curseur est déplacé,
mais 'b' a bel et bien effacé le caractère '3'.

En fonction des caractéristiques de ton compilateur (gcc+glibc pour toi, et
peut-être aussi des normes Posix ou X/Open propres à ton environnement) tu
pourrais avoir plus de garanties dans un sens ou un autre, mais là je suis
incapable de savoir te renseigner plus, désolé.


Ce n'est pas grave. Je crois que tes explications me suffisent.

^? est la manière la plus habituelle pour un pilote de terminal (au sens
ci-dessus) de représenter le caractère DEL, dont le code est 127. Autrement
dit, ton terminal considère que la touche retour arrière est liée au
caractère 127, pas au caractère b (qui a le code 8 pour ton
implémentation).


Ces histoires de codages des caractères c'est toujours bien compliqué.

Voilà. J'ai tendance à penser qu'il y a comme un défaut au niveau de la
conformité à la norme avec ta configuration, mais
1) ce n'est pas grave
2) je n'en suis pas sûr
3) sachant que ta configuration est (probablement) un standard Unix, je
doute qu'il soit possible d'y remédier autrement qu'au niveau local en
changeant les paramètres de ta configuration.


Comme tu dis, ce n'est pas grave.

Voilà. Note bien que « retour en arrière » (ou « déplacement à gauche » pour
nous autres qui écrivons de gauche à droite) est une fonction différente de
« effacement du dernier caractère », même si les terminaux à écran auxquels
nous sommes tant habitués cela semble similaire.


Ouh la ! Non, je ne vois pas bien.

1) « déplacement à gauche »
2) « effacement du dernier caractère »

ne possède pas le même code ASCII ? Ce n'est pas la même chose. Si c'est
exact, en langage C, 'b' donne en sortie le « déplacement à gauche »,
mais c'est quoi pour « effacement du dernier caractère » ?


Merci pour ta réponse. :-)


François

Avatar
Jean-Marc Bourguet
Copie sur fr.comp.os.unix

Francois writes:

[confusion DEL, BS, et terminaux dans le cadre de l'apprentissage du C]


Le sujet est compliqué et bourré d'histoire... une recherche sur le Web et
sur alt.folklore.computers avec des mots clés adéquats (BackSpace, Rubout,
terminal, Debian Keyboard Policy,...) devrait fournir de l'info à ceux qui
en veulent plus.


On a deux touches sur nos claviers: BackSpace et Del. Les ancêtres de ces
touches sur les terminaux et équipements antérieurs (tels que les machines
permettant de préparer les cartes et les rubans perforés) ont eu des
fonctions différentes. Depuis un certain nombre d'années, la tendance est
de se standardiser sur les comportements suivant
BackSpace efface le caractère précédant le curseur
Del efface le caractère suivant le curseur
au moins dans un contexte d'édition de texte. Mais n'a pas toujours été le
cas, même avec des programmes conçus pour des PC.

Les terminaux n'interprétant pas ces touches eux-mêmes et transmettant un
code pour elle ont aussi varié dans leur comportement. Il y a deux grandes
familles, plus des variantes dont je ne parlerai pas.
BackSpace 8 (BS) 127 (DEL)
Del 127 (DEL) 27 91 51 126 (ESC [ 3 ~)
Debian (et donc Ubuntu que tu utilises) a décidé de standardiser tous ses
émulateurs de terminaux sur la seconde colonne ce qui parmet aux trois
séquences de touches CTRL-H (qui génère BS partout où ça génére une
séquence de caractères à ma connaissance), BackSpace et Del d'être
distingables (l'alternative ne permet pas de distinguer BackSpace de
CTRL-H).

Les terminaux et autres équipements interprétant des séquences de
caractères (par exemple des imprimantes) traduisent généralement BS par un
retour à la position précédente (donc e BS ' permet d'avoir é). Les autres
séquences citées ici n'ont pas d'interprétation commune que je connais.

Unix place entre le terminal (souvent de nos jours un programme qui agit
comme un terminal le ferai) et l'application une couche qui s'occupe d'un
certain nombre de choses, dont:
- un petit éditeur de ligne permettant de corriger ses fautes de frappe
(attention, de nos jours les shells et pas mal d'application utilisent
leur propre éditeur de ligne, plus puissant)
- générer des signaux quand on appuye sur certaines touches
- de générer un echo des caractères entrés
Cette couche est paramétrable, soit par le programme stty qui va alors
changer les paramétres jusqu'à ce qu'ils soient changés à nouveau, soit par
une API -- et le bon usage est alors de remettre à la fin de son programme
les paramètres tels qu'on les a trouvés. Parmi ce qui est paramétrable, il
y a entre autres les caractères utilisés pour l'éditeur de lignes et la
génération de signaux.


Tu as déjà eu affaire à l'éditeur de ligne: c'est lui qui fait qu'un
programme ne reçoit généralement pas ce qui vient d'un terminal tant qu'une
fin de ligne ou un CTRL-D n'est pas reçu.

Dans ce fil tu as eu comme problème le terminal n'envoyait pas le caractère
auquel tu t'attendais pour la touche BackSpace (au fait, c'est souvent
configurable même si c'est rarement une bonne idée de changer la
configuration -- pour les terminaux de Gnome, c'est le menu Edit, Current
Profile..., Compatibility), utiliser CTRL-H l'envoyait. Je t'avais suggéré
la deuxième possibilité que l'éditeur en ligne du driver de terminal
interprétait le caractère et donc que ton programme ne le voyait jamais --
utiliser stty pour le désactiver était la solution que je te donnais.

A+

--
Jean-Marc
FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc
Site de usenet-fr: http://www.usenet-fr.news.eu.org