IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

Problème avec getchar().. (exo K&R)


Sujet :

C

  1. #1
    Membre averti
    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    19
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 19
    Par défaut Problème avec getchar().. (exo K&R)
    Bonsoir,

    J'ai un soucis avec un exo du K&R qui consiste a compter tout bêtement le nombre de caractères saisis par l'utilisateur à l'aide d'un getchar(). En fait le retour chariot est compté après chaque saisie, ce qui fausse donc la donne. Du coup si j'entre 3 caractère (1 par ligne), le résultat final (nc) sera 6 et non 3 !

    Je vous montre le code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include <stdio.h>
     
    main()
    {
      // Compte les caractères en entrée
     
      long nc;
     
      nc = 0;
      while (getchar() != EOF)
        ++nc;
     
      printf("%ld caractères(s)\n", nc);
    }
    C'est normal ou pas ?

    Merci.

  2. #2
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 496
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 496
    Par défaut
    Bonjour,

    Oui, c'est tout-à-fait normal : le retour à la ligne et le saut de ligne font partie des caractères de contrôle du code ASCII. Étant donné qu'à l'époque, on travaillait avec des terminaux passifs et que ceux-ci était reliés à l'unité centrale via une ligne série, il était nécessaire que ces « caractères de contrôle » fassent partie de cette table puisque c'est la seule chose que l'on pouvait envoyer et que c'était donc le seul moyen de piloter le terminal. C'est d'ailleurs la raison d'être de la touche « Ctrl » qui permet de les exprimer, même si peu de gens le savent encore aujourd'hui.

    À noter que tous les systèmes ne codent pas le retour à la ligne de la même façon. Unix n'utilise que le saut de ligne (tabulation verticale, code 10 ou 0x0a) pour signifier une nouvelle ligne (d'où « \n ») mais D.O.S. et Windows utilisent explicitement deux caractères par saut : « \r » puis « \n », respectivement 13 et 10, et qui servent à revenir en début de ligne (retour chariot) puis à sauter une ligne (tabulation verticale), ce qui était effectivement le mouvement effectué sur les machines à écrire.

    Ça tient debout, mais ces disparités entre systèmes restent assez ennuyeuses à gérer au quotidien. De toutes façons, la tendance est aujourd'hui à l'UTF-8 qui, par nature, peut utiliser de un à quatre codes successifs pour représenter un même caractère. On ne peut plus faire l'amalgame « 1 code = 1 caractère » et du coup, la différence entre DOS et Unix sur les retours à la ligne devient moins génante.

    À noter enfin qu'EOF n'est pas un caractère d'ASCII mais un marqueur extérieur à cette table. Il sert à indiquer que la lecture du flux a atteint sa fin pour une raison quelconque : soit c'est vraiment la fin du fichier (EOF = End Of File), soit c'est un tube refermé par l'écrivain (typiquement le cas quand on saisit des touches au clavier), soit une erreur s'est produite, indiquée le cas échéant par ferror().

  3. #3
    Membre averti
    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    19
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 19
    Par défaut
    Merci pour cette réponse très complète

  4. #4
    Membre éclairé Avatar de fantomas261
    Inscrit en
    Avril 2007
    Messages
    486
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 486
    Par défaut
    bonjour
    je voudrais savoir pour la valeur de la constante EOF s'écrit avec des parenthèses ?
    merci

  5. #5
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 496
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 496
    Par défaut
    Non, EOF est une macro #define (qui vaut généralement « -1 » mais on n'est pas censé le savoir).

    C'est pour cette raison que fgetc() et d'autres fonctions renvoient un « int » et pas un « char » : elles renvoient un type entier un peu plus grand qui puissent coder toutes les valeurs d'un char plus certaines autres pour que l'on puisse clairement faire le distingo entre les deux.

  6. #6
    Membre éclairé Avatar de fantomas261
    Inscrit en
    Avril 2007
    Messages
    486
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 486
    Par défaut
    Pourquoi ceux qui ont crées la langage C ont définit EOF comme une macro et non une constante ?
    Quel est l’intérêt de définir une macro sans paramètre ?
    merci

  7. #7
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    - EOF est antérieur à const.
    - en C l'utilisation de variables const n'est pas permise dans les expressions constantes (le plus génant dans le cas de EOF doit être après un case; en passant en C++ c'est autorisé)

  8. #8
    Membre éclairé Avatar de fantomas261
    Inscrit en
    Avril 2007
    Messages
    486
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 486
    Par défaut
    et pourquoi on a :
    #define EOF (-1) et non #define EOF -1 ?

  9. #9
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par fantomas261 Voir le message
    et pourquoi on a :
    #define EOF (-1) et non #define EOF -1 ?
    Beaucoup ont l'habitude de mettre systématiquement des parenthèses autour d'une expression dans une macro et autour de chaque argument. Sans cette précaution, il est facile d'écrire des macros qui vont être évaluées différemment suivant le contexte. Dans le cas présent, je ne vois pas directement de contexte où le problème pourrait se produire, ce qui ne garanti pas que la précaution est inutile.

  10. #10
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    parce que si un gugus écrit -EOF, ca donne bien -(-1), donc 1, qui compile, plutot que --1, qui ne compile pas.

  11. #11
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par leternel Voir le message
    parce que si un gugus écrit -EOF, ca donne bien -(-1), donc 1, qui compile, plutot que --1, qui ne compile pas.
    Les macros sont définies sur les symbles, -EOF donnerait trois symboles, - - 1, si EOF était définit comme -1.

    (Le simple fait que ça évite de se poser des questions est pour moi une raison suffisante d'être systématique sur les parenthèses quand on écrit des macros.).

  12. #12
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 496
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 496
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    Les macros sont définies sur les symbles, -EOF donnerait trois symboles, - - 1, si EOF était définit comme -1.
    Euh, es-tu sûr de cela ?

    Citation Envoyé par leternel Voir le message
    parce que si un gugus écrit -EOF, ca donne bien -(-1), donc 1, qui compile, plutot que --1, qui ne compile pas.
    Chez moi, ça compile (avec GCC 4.6.3). Le code suivant :

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #include <stdio.h>
     
    #undef EOF
    #define EOF -1
     
    int main (void)
    {
        printf ("%d\n",EOF);
        printf ("%d\n",-EOF);
        printf ("%d\n",EOF EOF);
     
        return 0;
    }

    … une fois traduit avec « gcc -E », donne :

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    int main (void)
    {
        printf ("%d\n",-1);
        printf ("%d\n",- -1);
        printf ("%d\n",-1 -1);
     
        return 0;
    }

    Donc, à la deuxième ligne, un espace a été explicitement inséré, tandis que les autres sont restés en l'état. Et ce même en C89. Je n'ai pas réussi à trouver le passage de la norme qui traite de cela, donc je ne sais pas si c'est quand même défini dedans ou si c'est GCC qui comble un « comportement indéterminé ».

  13. #13
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par Obsidian Voir le message
    Euh, es-tu sûr de cela ?
    Citation Envoyé par C90
    A preprocessing directive of the form
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    # define identifier replacement-list new-line
    defines an object-like macro that causes each subsequent instance of the macro name to be replaced by the replacement list of preprocessing tokens that constitute the remainder of the directive.
    De plus, l'existence de ## montre bien que le remplacement n'est pas du pur texte destiné à être rescanné.

  14. #14
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 496
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 496
    Par défaut
    Ça d'accord, c'est la définition des macros telles qu'on les connaît dans leur forme la plus courante, et ça signifie exactement :

    Une directive de pré-traitement de la forme :

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    # define identifiant liste-de-remplacement retour-à-la-ligne

    … définit une macro semblable à un objet provoquant le remplacement de toutes les instances suivantes du nom de la macro par la liste de remplacement de lexons qui constituent le reste de la directive.

    … mais je ne vois toujours pas pourquoi un « -1 » devrait être décomposé en deux symboles distincts s'il ne l'est pas à la base.

  15. #15
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    À la base, -1 c'est deux lexèmes, pas un seul.

  16. #16
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    Les macros sont définies sur les symbles, -EOF donnerait trois symboles, - - 1, si EOF était définit comme -1.

    (Le simple fait que ça évite de se poser des questions est pour moi une raison suffisante d'être systématique sur les parenthèses quand on écrit des macros.).
    J'avais eu une expérience différente, mais avec un autre compilateur (je ne sais d'ailleurs plus lequel)

  17. #17
    Membre éclairé Avatar de fantomas261
    Inscrit en
    Avril 2007
    Messages
    486
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 486
    Par défaut
    j'obtiens 2 à l’exécution
    1 à l exécution

  18. #18
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 496
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 496
    Par défaut
    Citation Envoyé par fantomas261 Voir le message
    j'obtiens 2 à l’exécution
    1 à l exécution
    Il faut regarder la grammaire du langage ainsi que le chapitre 5 de la norme, § 5.1.1.2 « Translation phases » :

    Le flux est découpé en « preprocessing tokens », puis les macros sont développées, et le résultat est enfin ré-analysé pour former les tokens définitifs qui, eux, vont pouvoir être compilés. Par ailleurs, à la section 6.4, on lit :

    6.4 Lexical elements
    Syntax
    1
    token:
    keyword
    identifier
    constant
    string-literal
    punctuator

    preprocessing-token:
    header-name
    identifier
    pp-number
    character-constant
    string-literal
    punctuator
    each non-white-space character that cannot be one of the above
    Ce qui veux dire que les preprocessing tokens sont capables de reconnaître dès le départ les identifiants (soit les symboles qui ne commencent pas par un chiffre, par exemple les noms de variables), les nombres et quelques autres choses. Et tout ce qui ne rentre pas dans ces cas de figure est considéré comme « un mot » qui tombe donc automatiquement dans le dernier.

    Par contre, la grammaire des pp-numbers ne tient pas compte du signe, qui sera donc interprété comme un lexème distinct. Toujours est-il qu'au moment de passer à la phase suivante, le compilateur sait déjà que EOF est en fait « - » (punctuator) + « 1 » (pp-number). Donc, le fait d'avoir découpé ça en pré-tokens d'un certain nombre de catégories permet justement de gérer les cas particulier quand il y a lieu de le faire et de revenir à un développement classique pour tous les autres.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Problèmes avec des exos de débutant
    Par Seedockh dans le forum Langage SQL
    Réponses: 8
    Dernier message: 11/06/2010, 14h57
  2. probléme avec cin et getchar()
    Par open_source dans le forum C++
    Réponses: 4
    Dernier message: 17/12/2007, 20h29
  3. problème avec un exo
    Par frost80500 dans le forum C#
    Réponses: 11
    Dernier message: 19/11/2007, 11h00

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo