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 :

Écrire EOF sur un flux


Sujet :

C

  1. #1
    Membre très actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2009
    Messages
    172
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2009
    Messages : 172
    Par défaut Écrire EOF sur un flux
    Bonjour,

    Suite à un problème que j'ai rencontré quelques jours auparavent et donv j'ai parlé sur le forum http://www.developpez.net/forums/d11...pe-eof-non-lu/ j'en suis arrivé à "débattre" sur le fait de pouvoir écrire un EOF (End Of File) sur un flux sans que le flux ne fermé. Je pensais que cela devait être possible d'après le peu de chose que j'ai lu dessus.
    - puts qui le convertit en caractère avant de l'utiliser.
    - Macro implémentée dans la libc.

    Mais l'on m'a répondu que ce n'était qu'une macro pour tester le retour des fonctions comme fread() (ce que je trouve un peu bizarre (voi topic)). Je n'ai Pas remis sa Parole en doute mais voila qu'en me documentant sur l'unicode je tombe sur une nouvelle macro, WEOF. Donc je suis maintenant presque sur qu'il doit être possible de spécifier un EOF dans un flux sans pour autant fermer ce flux.

    Donc je voulais avoir la confirmation par un autre expert que cela est vraiment impossible et si c'est possible. Comment faire, quelle fonctiln doit on appeler (vu que DE CE QUE J'AI COMPRIS puts() etc... Effectuent une conversion en caractère ansi ou unicode avant d'écrire). Car les bouts de code que je cite dans le sujet précédent ne marchent tout simolement pas! Cela vient-il de ctags?

    Merci

  2. #2
    Membre très actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2010
    Messages
    254
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2010
    Messages : 254
    Par défaut
    Pourquoi vouloir absolument écrire un EOF? Déja oui écrire un EOF dans un flux (que ce soit possible ou non) ferme le flux (que ce soit un pipe, une socket...). En réseau, quand on envoie un paquet via une socket, en général à la fin de cet envoie on met un \n pour signaler que c'est bien la fin du paquet. Pourquoi ne pas faire la même chose avec ton pipe?

    Et pour revenir au sujet d'est-il possible d'écrire un EOF sans fermer un flux, la réponse est probablement pas. Sur un système Unix, TOUT est fichier, ce qui veut dire que même les flux (peux importe lesquels) sont des fichiers. Or un EOF représente la fin d'un fichier. Donc si tu écrit un EOF dans un flux, tu lui signal qu'il est arrivé à la fin et donc il s'arrete.

  3. #3
    Membre très actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2009
    Messages
    172
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2009
    Messages : 172
    Par défaut
    Bonjour,

    As tu lu la discussion que j'ai cité? L'utilité y est donné. Si je suis sensé lancer des milliers un processus qui attend un EOF sur un flux dans lequel tu écris pour se fermer, c'est plus rapide et simple d'écrire directement EOF dans le flux plutôt que de devoir fermer le fd à chaque fois.

    Ce sera plus clair si tu lisais la discussion que je n'ai pas poster pour rien! (les derniers messages sont le sujet même de ce topic!)

    Merci

  4. #4
    Membre très actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2010
    Messages
    254
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2010
    Messages : 254
    Par défaut
    Pas besoin d'être agressif bonhomme. Sinon même si tu peux écrire un EOF dans un flux, ça le fermera.

  5. #5
    Membre Expert
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 104
    Par défaut
    EOF est justement une valeur spéciale ne correspondant pas à un caractère.

    Je vais te donner un exemple. Quand on lit le man de fgetc, on trouve ceci :
    fgetc() lit le caractère suivant depuis le flux stream et le renvoie sous forme d'un unsigned char, transformé en int, ou EOF en cas d'erreur ou de fin de fichier.
    Cette fonction est là pour renvoyer le caractère du flux en question (1 octet), mais elle est conçue également pour indiquer si le fichier est terminé ou si une erreur est survenue.
    Un caractère fait 1 octet. La valeur retournée est comprise entre 0 et 255, ce qui correspond à la plage d'un unsigned char. Comment alors la fonction doit-elle s'y prendre pour renvoyer une valeur spéciale correspondant à une erreur, mais qui ne doit surtout pas être confondue avec la valeur d'un caractère lu sur le flux ? Il lui suffit tout simplement de renvoyer une valeur de, non pas 1 octet, mais de >=2 octets. Et EOF est justement une valeur entière qui n'est pas comprise entre 0 et 255. Elle vaut souvent (toujours ?) -1, afin qu'elle ne soit justement pas confondue avec la valeur d'un caractère, dont la valeur est comprise entre 0 et 255.

    Donc, c'est la raison pour laquelle la doc de fgetc indique que le caractère lu sur le flux est d'abord un unsigned char (valeur entre 0 et 255), mais qu'il est ensuite converti en int (dont la taille est de 2 ou 4 octets), afin que la fonction permette justement d'envoyer soit la valeur du caractère lu (unsigned char casté en int, ce qui ne change pas sa valeur), soit la valeur spéciale EOF (-1 codé en int) en cas d'erreur ou de fin de fichier. Si EOF était codé sur un seul octet, il serait immanquablement confondu avec le caractère 255 (car -1, valeur de EOF, correspond à 255 en valeur non signée 8 bits) ; cela poserait un gros problème.

    Et si je voulais utiliser fputc pour "envoyer" EOF sur un flux, ce EOF serait considéré par la fonction comme un caractère normal. En fait, il serait casté en unsigned char, ce qui enverrait le caractère 255 sur le flux et non EOF.

    J'ai pris comme exemple fgetc / fputc pour t'expliquer le principe. Mais ça marche comme ça partout. Je ne suis pas calé en matière de païpe (), mais comme il s'agit de fichiers, cela doit fonctionner de la même manière.

  6. #6
    Membre très actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2009
    Messages
    172
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2009
    Messages : 172
    Par défaut
    Ok alors autant pour moi, Tout est devenu beaucoup plus clair avec ton explication sur les casts jeroman.

    Donc si j'ai bien compris, la macro EOF sert à désigner la valeur retour envoyé par fgetc une fois casté en int. Jusque là ok çà explique d'ailleurs pourquoi fread() renvoie un size_t et non un char * (qui paraissait plus logique) et pourquoi une macro pour l'unicode. Je dormirai déjà moins bête (je débute encore en C sous Linux, et en C tout court d'ailleurs). Mais j'aurai encore une petite question à te poser :


    Ce que je n'arrive vraiment pas à comprendre c'est pourquoi cette valeur spécialement (-1). Dès le moment où cette valeur est castée en int pourquoi ne pas avoir dit qu'un (int) -1 correspondrait à un EOF alors que toute autre valeur qui ne correspondrait pas à un char casté en int correspondrait à une erreur (je ne sais pas si je suis assez clair mais bon... Tout se joue sur les 3 octet de tête). Cela n'aurait-il pas simplifier les choses, on n'aurait pas besoin de vérifier effectivement la fin du fichier ou une erreur avec un feof() et un ferror().


    Merci merci merci pour tes réponses.

  7. #7
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 442
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

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

    Citation Envoyé par baccali Voir le message
    Ce que je n'arrive vraiment pas à comprendre c'est pourquoi cette valeur spécialement (-1). Dès le moment où cette valeur est castée en int pourquoi ne pas avoir dit qu'un (int) -1 correspondrait à un EOF alors que toute autre valeur qui ne correspondrait pas à un char casté en int correspondrait à une erreur (je ne sais pas si je suis assez clair mais bon... Tout se joue sur les 3 octet de tête). Cela n'aurait-il pas simplifier les choses, on n'aurait pas besoin de vérifier effectivement la fin du fichier ou une erreur avec un feof() et un ferror().
    Parce que toutes ces histoires de transtypages ne sont pas dues à des définitions formelles mais à des considérations techniques : « char » est un type servant à coder un caractère et, par définition, toutes les valeurs qu'il peut prendre représentent toujours un caractère, a priori valide.

    Si tu veux transmettre des informations supplémentaires, tu n'as pas le choix : soit tu fais une structure, ce qui compliquerait considérablement les choses dans ce cas précis, soit tu utilises un domaine plus grand.

    D'autre part, il n'y a pas de différence de représentation entre les entiers en binaire naturel signés et non signés : c'est simplement l'interprétation que le processeur va en faire qui va différer (de la même façon que, sur un compteur kilométrique, « 999999 » peut être interprété soit comme presque un million de kilomètres parcourus, soit comme un seul kilomètre en marche arrière).

    Par conséquent, quand tu castes un « char » vers un « unsigned char », sa représentation reste identique, mais tu es sûr que les valeurs représentées sont toutes positives. En plaçant le résultat dans un int, maintenant, tu es sûr également qu'une valeur négative ne pourra donc jamais représenter un caractère valide.

  8. #8
    Membre très actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2009
    Messages
    172
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2009
    Messages : 172
    Par défaut
    Bonjour Obsidian et merci de ton attention!

    Citation Envoyé par Obsidian Voir le message
    Si tu veux transmettre des informations supplémentaires, tu n'as pas le choix : soit tu fais une structure, ce qui compliquerait considérablement les choses dans ce cas précis, soit tu utilises un domaine plus grand.
    Oui, certes, mais ce que je voulais dire c'est puisque là on caste d'un (char) vers un (int) le problème ne se pose plus vu que ça nous laisse 3 octets en plus. Je pense avoir compris ta première phrase mais justement le principe y est, on a toujours des octets en plus initialisés à zéro pour garder la valeur du caractère puisque par "convention", on caste vers plus d'octets. (ce qui voudrait dire par exemple qu'en utf-32 fgetc renverrait une valeur sur 64 bit)

    Puisqu'on a donc commencé à utiliser ces octets en plus pour représenter un (int) -1, pourquoi ne pas continuer à utiliser les autres bits pour dire par exemple que (int) +/-5000 correspond à une erreur?

    Ou alors j'ai mal compris le message de jeroman! Vous savez je comprend vite mais faut m'expliquer longtemps

  9. #9
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    1 515
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France

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

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 515
    Par défaut
    Parce que c'est comme ça et pis c'est tout Si on avait mis un code d'erreur dans la valeur de retour, il y en a qui demanderaient pourquoi on n'a pas remonté l'erreur dans errno. Il y a toujours plusieurs façon de façon de faire la même chose, il faut bien en choisir une.

    WEOF c'est exactement comme EOF, sauf que c'est utilisé par certaines fonctions qui travaillent sur les wide-characters. Par exemple fgetwc(), qui retourne WEOF comme fgetc() retourne EOF.

  10. #10
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 442
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 442
    Par défaut
    Effectivement, je n'avais pas lu ta dernière phrase.

    En fait, c'est plutôt le terme « EOF » qui n'est plus totalement approprié, mais il est impossible d'en changer pour des raisons de compatibilité ascendante. Et comme généralement, les erreurs ne sont pas récupérables, cela signifie que l'on atteint la fin des données lisibles, quelle qu'en soit la raison.

    D'autre part, à l'époque où ces spécifications ont été établies, il y a de fortes chances pour que les entiers int aient encore été codés sur 16 bits au lieu de 32 (ça laisse quand même de la marge).

    Mais surtout, le passage de « char » à « int » n'est là que pour garantir la place nécessaire pour coder un caractère plus un marqueur. On ne peut absolument pas se fier au signe de la donnée pour affirmer qu'il s'agit de l'un ou de l'autre, pas plus que l'on ne peut garantir que EOF vaudra toujours -1, partout. Sur un plan formel, le seul moyen sûr de savoir si la donnée renvoyée est un marqueur est de la comparer avec ledit marqueur :


    Si l'on multipliait ces marqueurs, alors il faudrait tous les vérifier à chaque fois qu'on lirait un caractère :

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
      if (c==EOF || c==IOERROR || c==PERMISSIONDENIED || … )

    Ce serait ingérable. Le marqueur unique « EOF » nous permet donc de vérifier rapidement si la donnée reçue est un caractère valide ou pas. Dans le second cas, il nous appartient de vérifier quelle est l'erreur en évaluant les bonnes fonctions.

  11. #11
    Membre très actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2009
    Messages
    172
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2009
    Messages : 172
    Par défaut
    Citation Envoyé par Obsidian Voir le message
    En fait, c'est plutôt le terme « EOF » qui n'est plus totalement approprié, mais il est impossible d'en changer pour des raisons de compatibilité ascendante. Et comme généralement, les erreurs ne sont pas récupérables, cela signifie que l'on atteint la fin des données lisibles, quelle qu'en soit la raison.
    Je commençais un peu à m'en douter oui!


    Citation Envoyé par Obsidian Voir le message
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
      if (c==EOF || c==IOERROR || c==PERMISSIONDENIED || … )
    Et pourquoi pas :
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     while (c >= CHARMAX) {
    /* traitement normal */
    }
     
    if (c == EOF){
    /* fin NORMALE du fichier */
    } else {
    /* erreur, avec la possibilité de traiter l'erreur sans appeler d'autres fonctions */
    }

    Je trouve çà beaucoup plus avantageux et plus simple que de devoir appeler une fonction par test avec tout l'overhead que çà implique car là avec une seule fonction on peut tester toutes les conditions dont tu parles. Mais c'est sûr là je chipote

    Je passe en résolu! Merci de votre patience.

  12. #12
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 442
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 442
    Par défaut
    Parce que, comme dit dans mon précédent commentaire, c'est le « >= » qui pose problème.

    De plus, si tu fais d'abord une comparaison avec « >= » puis que tu vérifies les codes d'erreurs ensuite, ça revient exactement au même qu'avec la méthode actuelle, qui vérifie d'abord EOF et qui appelle ferror(), feof(), etc. ensuite. En plus, cette dernière interface est extensible à l'infini, et sans effet de bord.

  13. #13
    Membre très actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2009
    Messages
    172
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2009
    Messages : 172
    Par défaut
    J'avoue que vu comme çà l'algo est le même. Et de toute façon ce qui n'est pas fait dans mon programme pour tester l'erreur est de toute façon fait dans la lib. (En pratique on ne gagnerait que quelques milli secondes, et encore, si l'on voulait effectivement traiter toutes les erreurs )

    Sinon je voudrai revenir sur çà :
    Citation Envoyé par Obsidian Voir le message
    Par conséquent, quand tu castes un « char » vers un « unsigned char », sa représentation reste identique, mais tu es sûr que les valeurs représentées sont toutes positives. En plaçant le résultat dans un int, maintenant, tu es sûr également qu'une valeur négative ne pourra donc jamais représenter un caractère valide.
    Citation Envoyé par Obsidian
    Parce que, comme dit dans mon précédent commentaire, c'est le « >= » qui pose problème.
    Dès le moment où l'on sait que la valeur renvoyé est signed (OU unsigned selon le proto) pourquoi dis tu que cela pose problème? J'ai pas tout saisi!

  14. #14
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 442
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 442
    Par défaut
    Citation Envoyé par baccali Voir le message
    Dès le moment où l'on sait que la valeur renvoyé est signed (OU unsigned selon le proto) pourquoi dis tu que cela pose problème? J'ai pas tout saisi!
    Le fait de caster d'abord en unsigned char permet de garantir que toutes les valeurs seront considérées positives, et qu'elles le resteront une fois transformées en int, ce qui nous permet d'être sûrs que -1, du coup sera en dehors des caractères valides. Ok.

    MAIS … ce ne sont là que des considérations techniques qui nous permettent d'arriver à nos fins en respectant la spécification. C'est donc quelque chose qui doit être considéré comme une recommandation à l'implémentation du compilo, et pas comme une guideline du développeur.

    En plus ce n'est pas forcément vrai : un byte n'est pas toujours un octet. C'est en fait l'unité minimum soit manipulée par le processeur, soit reconnue par le langage C. Il se trouve que, par définition sizeof (char) = 1 byte et que, d'autre part, un char est l'unité suffisamment grande pour représenter tout le jeu de caractères de base à l'exécution. Donc, si tu fonctionnes sur une machine entièrement 16 bits (dans laquelle chaque adresse correspond à un mot de seize bits indivisible et pas à un octet), il y a de fortes chances pour qu'un char soit codé sur le même nombre de bits qu'un int.

    Comme le jeu de caractères de base est spécifié par la norme, on sait exactement combien de caractères il contient, et on sait que ce nombre tient sur moins de seize bits et que, donc, un bon nombre de combinaisons ne correspondront à aucun caractère valide.

    Dès lors, tu peux choisir une de ces valeurs et l'affecter à EOF. Mais il n'y a pas de formule mathématique universelle qui te permette de le faire.

  15. #15
    Membre très actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2009
    Messages
    172
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2009
    Messages : 172
    Par défaut
    Oui c'est pour cela que je précisais que je parlais de principe et non de ce cas particulier. J'ai pris le cas le plus facile/général mais c'est aussi pour cela que je disais que si si un char faisait 32 bit, sur un système différent ou en utf-32, fgetc() renverrait une valeur sur plus de 32 bit (64 par exemple). Voir même il faudrait utiliser une fonction dérivée (comme wprintf).

    Si la taille d'un char "basique" varie selon le système je pense que de toute façon la libc aussi s'adapterait selon le système. Dès le moment où le principe de fgetc() est tel qu'il renverra forcément une valeur sur un nombre de bits plus grands que ceux nécessaires aux char je ne vois pas de problème dans une comparaison "<" ou ">". Si j'ai bien compris ton message!

    Sinon pour EOF je me disais juste qu'il aurait été plus "pratique" pour le développeur applicatif de ne pas avoir à invoquer 10 fonctions pour tester 10 "types d'erreur" quand une simple comparaison de nombre, sous forme de macro suffirait (mais on est d'accord qu'aujourd'hui ma proposition relève d'un maniaque! pour quelques nanosecondes de gagnées!).

    Toutefois, je pense qu'une fonction qui ferait tous ces tests pour nous et utiliserait ces bits en plus pour nous donner ne serait-ce que le type d'erreur (->genre Au dessus de telle valeur c'est une erreur bénigne, voire une EOF normale, au dessus de telle valeur c'est une erreur un peu plus grave, accès, flux inexistant, au dessus de telle valeur ce sont les I/O etc..., avec bien sûe des macros et des valeurs précises correspondant à une erreur précise<-). Je pense qu'une telle fonction n'aurait peut-être pas sa place dans la libc mais serait une bonne fonction qui nous éviterait PARFOIS , pas mal de lignes de code. Je dirai même même rarement, juste quand on veut un degré de précision assez élevé! Je débute encore en C sous Linux donc je sais pas si on a souvent besoin de tester ces erreurs sur des flux. On verra quand j'aurais pris de la bouteille



    Mais j'ai peut-être mal saisi ce que tu voulais dire pour les comparaisons. Sinon, je te remercie encore de ta patience, pour les réponses que tu m'as fourni et cette petite discussion.

    Cordialement.

  16. #16
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 442
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 442
    Par défaut
    Dès le moment où le principe de fgetc() est tel qu'il renverra forcément une valeur sur un nombre de bits plus grands que ceux nécessaires aux char je ne vois pas de problème dans une comparaison "<" ou ">". Si j'ai bien compris ton message!
    D'abord, on ne peux pas être sûr à 100% qu'un int sera forcément plus grand qu'un char mais ça, à la limite, ce n'est pas notre problème puisque la norme établit que fgetc() renvoie un int. Le problème est surtout sur la forme : EOF est censé être un « non-caractère » et, à ce titre, il n'a pas de relation d'ordre avec eux.

    Le fait de caster en unsigned char puis en int est donc une solution technique pour faire cohabiter les deux proprement, et une recommandation à suivre par défaut quand c'est possible.

    Sinon pour EOF je me disais juste qu'il aurait été plus "pratique" pour le développeur applicatif de ne pas avoir à invoquer 10 fonctions pour tester 10 "types d'erreur" quand une simple comparaison de nombre, sous forme de macro suffirait (mais on est d'accord qu'aujourd'hui ma proposition relève d'un maniaque! pour quelques nanosecondes de gagnées!).
    En fait, il n'y en a pas dix. C'est ça l'idée. Il y a le cas de la fin normale du fichier, et celui de la fin prématurée pour cause d'erreur. Tu peux considérer ça comme un cas particulier de fin de fichier. Ensuite, la cause de l'erreur, elle, relève de la programmation système et n'a donc rien à faire, toujours a priori, dans la norme C.


    Maintenant, il faut aussi retenir que la norme C est ancienne. Le langage C a inspiré la plupart des langages modernes et ceux-ci ont à chaque fois tirés les leçons de l'expérience. Après 40 ans d'existence, les vénérables langages C et systèmes Unix s'en tirent plutôt pas mal…

  17. #17
    Membre très actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2009
    Messages
    172
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2009
    Messages : 172
    Par défaut
    Tu pars du principe que la convention stipule que fgetc renvoie un int quel que soit le système, c'est vrai que la doc est ambigüe sur ce sujet mais comme j'ai dit je pense qu'on peut raisonnablement supposer que la lib s'adapterait (le proto de la fonction donc...) car si la lib ne s'adapte pas sur un système où un char est codé sur le même nombre de bit qu'un int on pourrait aussi se demander comment différencier un EOF d'un char non? Ou alors il faudrait voir à utiliser des dérivées adaptées à ces systèmes des fonctions de la lib.

    Sinon pour la place d'une telle fonction dans la libc il existe bien des fonctions appartenant à la lib permettant de déceler la nature d'un problème système. Je ne pense pas que la lib ne doivent rien à voir avec le système lui même. Ils coopèrent. Sans lib pas de linux et d'ailleurs errno est bien un "truc" de la libc.

    Donc je pense que si une telle fonction n'est pas intégré c'est car elle ne serait que rarement utilisée. Car elle ferait beaucoupbde travail dont on aurait pas forcément besoin.

  18. #18
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 442
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 442
    Par défaut
    Citation Envoyé par baccali Voir le message
    Tu pars du principe que la convention stipule que fgetc renvoie un int quel que soit le système, c'est vrai que la doc est ambigüe sur ce sujet mais comme j'ai dit si la lib ne s'adapte pas sur un système où un char est codé sur le même nombre de bit qu'un int on pourrait aussi se demander comment différencier un EOF d'un char non?
    C'est plus qu'une convention : le langage C est normalisé. C'est un document désormais ratifié et publié par l'ISO. La norme décrit en détails et de façon stricte ce que doit être le langage C et comment il réagit. C'est cette même norme qui définit les éléments de la bibliothèque standard.

    « fgetc » en fait partie et est défini par un paragraphe qui lui est propre.

    7.19.7 Character input/output functions
    7.19.7.1 The fgetc function
    Synopsis
    1
    #include <stdio.h>
    int fgetc(FILE *stream);
    Description
    2
    If the end-of-file indicator for the input stream pointed to by stream is not set and a
    next character is present, the fgetc function obtains that character as an unsigned
    char converted to an int and advances the associated file position indicator for the
    stream (if defined).
    Returns
    3
    If the end-of-file indicator for the stream is set, or if the stream is at end-of-file, the end-
    of-file indicator for the stream is set and the fgetc function returns EOF. Otherwise, the
    fgetc function returns the next character from the input stream pointed to by stream.
    If a read error occurs, the error indicator for the stream is set and the fgetc function
    returns EOF.255)

    255) An end-of-file and a read error can be distinguished by use of the feof and ferror functions.
    Sinon pour la place d'une telle fonction dans la libc il existe bien des fonctions appartenant à la lib permettant de déceler la nature d'un problème système. Je ne pense pas que la lib ne doivent rien à voir avec le système lui même. Ils coopèrent. Sans lib pas de linux et d'ailleurs errno est bien un "truc" de la libc.
    J'entends par là que ce sont deux choses distinctes. L'exploitation de la bibliothèque standard te garantit que — en principe — ton programme sera universellement portable. Tout compilateur C qui se respecte doit implémenter ces fonctions de la manière décrite par la norme, sans prendre de largesses, sauf si la norme reste muette sur certains détails ou accorde explicitement une liberté.

    De l'autre côté, la programmation système relève de l'exploitation dudit système. Ça veut dire que tout ce que tu vas écrire dans ce contexte va être dépendant de l'O.S. que tu utilises. Par exemple, fopen() et fclose() sont des fonctions C et tu peux les utiliser partout. Par contre, open() et close() sont des fonctions UNIX et POSIX. Tu ne peux les utiliser que sur les systèmes qui reconnaissent cette dernière norme. Tu n'es pas sûr de les retrouver dans tous les contextes et, si elles existent, tu ne peux pas garantir non plus que ce ne sont pas des homonymes qui n'ont rien à voir avec celles que tu crois utiliser.

    En ce qui concerne EOF, donc, le langage C peut imposer un marqueur de fin de fichier puisqu'il définit la notion de gestion de fichiers en général. En revanche, l'erreur qui a provoqué cette fin ne peut pas être définie de manière universelle : ça dépend du système. Par exemple, « permission denied » n'existe que sur les systèmes qui gèrent des droits d'accès.

  19. #19
    Membre très actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2009
    Messages
    172
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2009
    Messages : 172
    Par défaut
    Citation Envoyé par Obsidian Voir le message
    C'est plus qu'une convention : le langage C est normalisé. C'est un document désormais ratifié et publié par l'ISO. La norme décrit en détails et de façon stricte ce que doit être le langage C et comment il réagit. C'est cette même norme qui définit les éléments de la bibliothèque standard.

    « fgetc » en fait partie et est défini par un paragraphe qui lui est propre.
    Je comprend exactement et je suis même totalement d'accord avec ce que tu dis Obsidian vu que c'est écrit comme tel (concernant la norme du moins) mais je pense que tu ne saisis pas bien ce que moi je veux dire! J'ai survolé la doc sur la libc, j'en connais les grandes lignes mais ce que je veux dire c'est que sur un système qui a des char de la taille des int (d'ailleurs as-tu des exemples de tels systèmes?), si tant est que ce système soit capable d'utiliser une libc respectant la norme, il serait obligé d'adapter la libc à son système ou alors on serait obligé de modifier la norme pour que ce système puisse l'intégrer (pour fgetc(), changer le int en une macro par exemple). Car à l'heure actuelle il est impossible pour un tel système de respecter la norme. Windows change bien sa "politique" et ses librairies standard (en créant des fonctions "extended", ou en remplaçant les précédentes fonctions par des macro pour s'adapter à l'ANSI ou l'UNICODE), et ils ne s'en portent pas plus mal bien au contraire! L'informatique et les normes évoluent, certains prévoient même des champs dans les structures déjà en place pour des changements futur, libc, POSIX et SUS comme Windows et la norme regorge de warnings concernant des changements futurs. çà se voit tous les jours, l'important étant de garder une compatibilité ascendante à travers les versions (d'où les fonctions "extended" et les macros au lieu du remplacement de la fonction même). Combien de norme du langage C ont vu le jour avant celle qu'on utilise actuellement ? 3 ou 4 je crois bien


    Citation Envoyé par Obsidian Voir le message
    J'entends par là que ce sont deux choses distinctes. L'exploitation de la bibliothèque standard te garantit que — en principe — ton programme sera universellement portable. Tout compilateur C qui se respecte doit implémenter ces fonctions de la manière décrite par la norme, sans prendre de largesses, sauf si la norme reste muette sur certains détails ou accorde explicitement une liberté.

    De l'autre côté, la programmation système relève de l'exploitation dudit système. Ça veut dire que tout ce que tu vas écrire dans ce contexte va être dépendant de l'O.S. que tu utilises. Par exemple, fopen() et fclose() sont des fonctions C et tu peux les utiliser partout. Par contre, open() et close() sont des fonctions UNIX et POSIX. Tu ne peux les utiliser que sur les systèmes qui reconnaissent cette dernière norme. Tu n'es pas sûr de les retrouver dans tous les contextes et, si elles existent, tu ne peux pas garantir non plus que ce ne sont pas des homonymes qui n'ont rien à voir avec celles que tu crois utiliser.
    Je n'ai jamais parlé des fonctions liées au noyau, je ne parle pas de read(), mais bien de la fonction fgetc() de la libc. Pour moi tu essayes de séparer deux choses qui ne s'excluent pas du tout et qui sont tellement liées qu'on peut les confondre. Les fonctions de la libc permettent de rendre ton appli universelle, tout en servant d'interface au système lui même. C'est comme si tu disais que le HAL sert à rendre ton appli/driver portable sans avoir quelques chose à voir avec le matériel sous-jacent! On parle de norme POSIX mais aussi de système compatible POSIX. La libc permet d'utiliser les mêmes fonctions quels que soient les systèmes......, pour interagir avec les dits systèmes! C'est pour cela que je dis qu'ils sont intrinsèquement liés. Certaines fonctions de la libc nous informent déjà sur les erreurs du système. Pourquoi serait ce si choquant qu'une fonction de plus le fasse?

    Citation Envoyé par Obsidian Voir le message
    En ce qui concerne EOF, donc, le langage C peut imposer un marqueur de fin
    de fichier puisqu'il définit la notion de gestion de fichiers en général. En revanche, l'erreur qui a provoqué cette fin ne peut pas être définie de manière universelle : ça dépend du système. Par exemple, « permission denied » n'existe que sur les systèmes qui gèrent des droits d'accès.
    Et pourtant...! La libc implémente bien des macro en rapport avec des erreurs système! Je ne dis pas non plus qu'une fonction comme fgetc() devrait te renvoyer des erreurs de l'UAC Windows mais certaines erreurs, au même titre que la libc qui les définit, sont universelles. Une erreur de mémoire insuffisante, de buffer trop petit ou de I/O error peuvent arriver sur n'importe quel système et errno.h est bien en rapport avec ces erreurs et non avec des erreurs spécifiques à chaque système. C'est pour çà que certains systèmes ont mis des fonctions comme GetLastError() en + (à la place) de errno.h.

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

Discussions similaires

  1. Réponses: 3
    Dernier message: 08/08/2006, 02h50
  2. Savoir si des données sont écrites sur un flux
    Par zapatta dans le forum Langage
    Réponses: 3
    Dernier message: 07/06/2006, 12h27
  3. Applet Java sur Boursorama (flux continu) - port 8000
    Par Invité dans le forum Applets
    Réponses: 4
    Dernier message: 02/02/2006, 23h05
  4. Une requête renvoyant EOF sur serveur (fonctionne ailleur)
    Par Tardiff Jean-François dans le forum ASP
    Réponses: 2
    Dernier message: 15/11/2005, 08h52
  5. [Servlet][Deb]envoyer image gif sur le flux http
    Par ptitBoutchou dans le forum Servlets/JSP
    Réponses: 15
    Dernier message: 09/04/2004, 10h12

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