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 :

Avis sur un programme


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé Avatar de _kal_
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Janvier 2006
    Messages
    178
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Janvier 2006
    Messages : 178
    Par défaut Avis sur un programme
    Bonsoir à tous,

    Je viens de réaliser un tout petit programme permettant de supprimer les retours à la ligne d'un fichier texte.

    J'aimerai connaitre vos reactions face à mon code, ma façon de gérer les erreurs. Ai-je procédé de la bonne façon ?

    Merci d'avance

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <string.h>
    #include <wchar.h>
    #include <locale.h>
     
    char *argv0;
     
    void
    usage()
    {
      fprintf(stderr, "Usage : %s <fichier_in> <fichier_out>\n", argv0);
      exit(EXIT_FAILURE);
    }
     
    void
    copyFile(FILE *fin, FILE *fout)
    {
      wint_t c;
     
      while ( (c = fgetwc(fin)) != WEOF )
        {
          if (c == L'\n')
    	c = L' ';
     
          if ( (fputwc(c, fout)) == WEOF)
    	{
    	  fprintf(stderr, "Erreur lors de l'ecriture vers le fichier de sortie\n");
    	  exit(EXIT_FAILURE);
    	}
        } 
    }
     
     
    int
    main(int argc, char *argv[])
    {
      setlocale(LC_ALL, "");
      argv0 = argv[0];
     
      if (argc != 3)
        usage();
     
      FILE *fin;
      FILE *fout;
     
      errno = 0;
      if ( (fin = fopen(argv[1], "r+")) == NULL )
        {
          perror(argv[1]);
          exit(EXIT_FAILURE);
        }
     
      errno=0;
      if ( (fout = fopen(argv[2], "w")) == NULL )
        {
          perror(argv[2]);
          exit(EXIT_FAILURE);
        }
     
      copyFile(fin, fout);
     
      errno = 0;
      if ( fclose(fin) == EOF )
        {
          perror(NULL);
          exit(EXIT_FAILURE);
        }
     
      errno = 0;
      if ( fclose(fout) == EOF )
        {
          perror(NULL);
          exit(EXIT_FAILURE);
        }
     
      return EXIT_SUCCESS;
    }
    PS: Ce programme est destiné à être executé dans un environnement Linux et la portabilité vers un autre OS n'est pas l'objectif de celui-ci.

  2. #2
    Membre émérite

    Profil pro
    Inscrit en
    Août 2003
    Messages
    878
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2003
    Messages : 878
    Par défaut
    Citation Envoyé par _kal_
    Bonsoir à tous,

    Je viens de réaliser un tout petit programme permettant de supprimer les retours à la ligne d'un fichier texte.

    J'aimerai connaitre vos reactions face à mon code, ma façon de gérer les erreurs. Ai-je procédé de la bonne façon ?

    Merci d'avance
    Bonsoir à toi,

    Pourquoi "char *argv0;" en variable globale ? Est-ce gênant de passer "argv[0]" comme argument à "usage()" ?
    Six "exit()" + un "return" dans le même programme...personnellement, jen'aime pas...
    Idem pour les fonctions qui ne renvoient pas de valeur (c'est lié).
    Pourquoi "r+" pour ouvrir le fichier à lire ?

  3. #3
    Membre confirmé Avatar de _kal_
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Janvier 2006
    Messages
    178
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Janvier 2006
    Messages : 178
    Par défaut
    Citation Envoyé par David.Schris
    Bonsoir à toi,
    Pourquoi "char *argv0;" en variable globale ? Est-ce gênant de passer "argv[0]" comme argument à "usage()" ?
    Non ce n'est pas génant. Par ailleurs, j'ai pris l'habitude de cette technique lors de la lecture d'un ouvrage (Méthodologie de la programmation en C). C'est utile si l'on veux utiliser argv[0] ailleurs dans le programme sans surcharger le prototype des fonctions. Mais ici, ce n'est pas le cas, donc j'vais changer mon code.

    Citation Envoyé par David.Schris
    Six "exit()" + un "return" dans le même programme...personnellement, jen'aime pas...
    Idem pour les fonctions qui ne renvoient pas de valeur (c'est lié).
    En effet, je viens de m'apercevoir que c'est pas trés jolie
    J'ai créé une fonction exit_if qui test la condition reçue en paramètre. Si elle est vraie, la fonction affiche un message d'erreur puis termine le programme.
    J'ai aussi modifié le prototype de la fonction copyFile qui renvoit à present une valeur, testé dans la fonction appellante à l'aide de EXIT_IF.
    Citation Envoyé par David.Schris
    Pourquoi "r+" pour ouvrir le fichier à lire ?
    En effet, c'est corrigé.

    exit_if.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    #ifndef   	EXIT_IF_H_
    # define   	EXIT_IF_H_
     
    #define EXIT_IF(condition, message) \
        exit_if(__FILE__, __LINE__, condition, #condition, message)
     
    extern void exit_if(char *fichier, int ligne, bool condition, char *code, char *message);
     
    #endif 	    /* !EXIT_IF_H_ */
    exit_if.c
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdbool.h>
    #include <wchar.h>
    #include "exit_if.h"
     
    void
    exit_if(char *fichier, int ligne, bool condition, char *code, char *message)
    {
      if (!condition)
        return;
     
      if (message == NULL)
        fwprintf(stderr, L"%s:%d: condition d'arrêt: \"%s\"\n", fichier, ligne, code);
      else
        fwprintf(stderr, L"%s:%d: %s\n", fichier, ligne, message);
     
      exit(EXIT_FAILURE);
    }
    delLine.c
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdbool.h>
    #include <wchar.h>
    #include <locale.h>
     
    #include "exit_if.h"
     
    static void
    usage(char *s)
    {
      fwprintf(stderr, L"Usage : %s <fichier_in> <fichier_out>\n", s);
      exit(EXIT_FAILURE);
    }
     
    static int
    copyFile(FILE *fin, FILE *fout)
    {
      wint_t c;
     
      while ( (c = fgetwc(fin)) != WEOF )
        {
          if (c == L'\n')
    	c = L' ';
     
     
          if (fputwc(c, fout) == WEOF)
    	return EXIT_FAILURE;
        } 
     
      return EXIT_SUCCESS;
    }
     
     
    int
    main(int argc, char *argv[])
    {
      setlocale(LC_ALL, "");
     
      if (argc != 3)
        usage(argv[0]);
     
      FILE *fin;
      FILE *fout;
     
      fin = fopen(argv[1], "r");
      fout = fopen(argv[2], "w");
     
      EXIT_IF(fin == NULL, "Erreur lors de l'ouverture du fichier d'entrée");
      EXIT_IF(fout == NULL, "Erreur lors de l'ouverture du fichier de sortie");
      EXIT_IF(copyFile(fin, fout) == EXIT_FAILURE, "Erreur lors de l'ecriture vers le fichier de sortie");
     
     
      EXIT_IF(fclose(fin) == EOF, "Erreur lors de la fermeture du fichier\n");
      EXIT_IF(fclose(fout) == EOF, "Erreur lors de la fermeture du fichier\n");
      return EXIT_SUCCESS;
    }
    J'ai voulu définir les prototypes de mes fonction avec un type wchar, mais c'était refusé à la compilation. Exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    static void
    usage(wchar *s)
    {
      fwprintf(stderr, L"Usage : %s <fichier_in> <fichier_out>\n", s);
      exit(EXIT_FAILURE);
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    kal@kal-desktop ~/work $ gcc -W -Wall -std=c99 -c delLine.c
    delLine.c:32: erreur: syntax error before «*» token
    delLine.c: Dans la fonction «usage» :
    delLine.c:34: erreur: «s» undeclared (first use in this function)
    delLine.c:34: erreur: (Chaque identificateur non déclaré est rapporté une seule fois
    delLine.c:34: erreur: pour chaque fonction dans laquelle il apparaît.)
    Une idée ?

  4. #4
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Félicitations, tu viens de recoder le système d'assertions.

    Pour les chaînes Wide: le type est wchar_t et non wchar.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  5. #5
    Membre confirmé Avatar de _kal_
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Janvier 2006
    Messages
    178
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Janvier 2006
    Messages : 178
    Par défaut
    Citation Envoyé par Médinoc
    Félicitations, tu viens de recoder le système d'assertions.

    Pour les chaînes Wide: le type est wchar_t et non wchar.
    Bah pas totalement, car à l'origine je voulais utiliser la fonction assert(). Par ailleurs, celle-ci n'affiche pas un message d'erreur trés parlant pour l'utilisateur, elle indique juste le code servant de condition lors de l'appel à assert. Moi je prefere les messages de perror(), ou alors de ma macro-fonction EXIT_IF que je défini moi même.

    Sinon, le type c'était bien wchar_t, j'ai pas encore l'habitude

    Citation Envoyé par Lunixinclar
    Juste un truc: une partie du traitement est dans le main, et l' autre dans la fonction. Mieux vaut tout mettre dans la fonction: on lui passe deux chemins de fichier, elle fait ses vérifications et son traitement puis retourne une valeur. Du coup le main devient très clair, tellement clair qu'on pourrait le noter:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    return ConversionFichierVersFormatMAC(FILE* ...);
    Exact, c'est ce que je vais faire. Le prototype de ma fonction sera alors :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    static int
    copyFile(char *in, char *out)
    Citation Envoyé par Lunixinclar
    J'ai l'impression que la fonction veut supprimer tous les LF mais les remplace par des espaces?
    Tout à fait, c'est juste un petit script perso qui m'a aidé à traiter une longue liste de paquet pour mettre à jour ma ubuntu, mais c'est une autre histoire. J'aurai pu le faire avec SED mais j'avais la flemme de cherche l'expression régulière kivabien, et comme j'étudie le C en ce moment, je me suis proposé de le coder en C

    Citation Envoyé par Lunixinclar
    Aussi, vérifier le pointeur juste après son initialisation, pas deux heures après
    Ok, c'est noté

    Citation Envoyé par PRomu@ld
    Oui, c'est vrai, et d'ailleur, l'utilisation d'un assert avec l'affichage de errno aurait fait exactement la même chose.
    Mais comment afficher le message de errno si on utilise assert? En effet, assert va terminer l'execution du programme si la condition testé est fausse, donc pas le temps de faire un perror()
    Y'a surement un truc qui a dû m'échapper ...

  6. #6
    Membre chevronné Avatar de Lunixinclar
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juillet 2006
    Messages
    416
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 416
    Par défaut
    wchar_t, puisque l18n.

    Sinon j'aime bien.

    Juste un truc: une partie du traitement est dans le main, et l' autre dans la fonction. Mieux vaut tout mettre dans la fonction: on lui passe deux chemins de fichier, elle fait ses vérifications et son traitement puis retourne une valeur. Du coup le main devient très clair, tellement clair qu'on pourrait le noter:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    return ConversionFichierVersFormatMAC(FILE* ...);
    Beaucoup d'applications GNU font comme ça.

    J'ai l'impression que la fonction veut supprimer tous les LF mais les remplace par des espaces?

    Aussi, vérifier le pointeur juste après son initialisation, pas deux heures après:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
      fin = fopen(argv[1], "r");
      fout = fopen(argv[2], "w");
     
      EXIT_IF(fin == NULL, "Erreur lors de l'ouverture du fichier d'entrée");
      EXIT_IF(fout == NULL, "Erreur lors de l'ouverture du fichier de sortie");
     
    //devient simlement
      fin = fopen(argv[1], "r");
      if (fin == NULL) puts("Erreur lors de l'ouverture du fichier d'entrée");
     
      fout = fopen(argv[2], "w");
      if (fout == NULL) puts("Erreur lors de l'ouverture du fichier de sortie");
    En effet il n'est pas vital de préciser la ligne où ça se passe. En revanche on peut respecter le style élaboré de la gestion d'erreur.

    Ce ne sont que des remarques persos, le principal c'est que ça marche. Il y a autant de façons d' écrire un programme qu'il y a de programmeurs.

  7. #7
    Expert confirmé
    Avatar de PRomu@ld
    Homme Profil pro
    Ingénieur de Recherche
    Inscrit en
    Avril 2005
    Messages
    4 155
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Vienne (Poitou Charente)

    Informations professionnelles :
    Activité : Ingénieur de Recherche
    Secteur : Enseignement

    Informations forums :
    Inscription : Avril 2005
    Messages : 4 155
    Par défaut
    Félicitations, tu viens de recoder le système d'assertions.
    Oui, c'est vrai, et d'ailleur, l'utilisation d'un assert avec l'affichage de errno aurait fait exactement la même chose.

    Six "exit()" + un "return" dans le même programme...personnellement, jen'aime pas...
    Ca n'est pas un problème, en programmation système, cela revient très souvent.

    Juste un truc: une partie du traitement est dans le main, et l' autre dans la fonction. Mieux vaut tout mettre dans la fonction
    Exact.

    return ConversionFichierVersFormatMAC(FILE* ...);
    Il faut faire attention, certains compilateurs n'aiment pas ce genre d'écritures. En effet, pour eux, le retour doit être une variable et pas une fonction. (il y a une option dans gcc pour le signaler).

  8. #8
    Membre Expert
    Avatar de Pragmateek
    Homme Profil pro
    Formateur expert .Net/C#
    Inscrit en
    Mars 2006
    Messages
    2 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Formateur expert .Net/C#
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 635
    Par défaut
    un "fgetws" dans un buffer puis recherche des caractères de saut de ligne ne serait il pas plus performant?

Discussions similaires

  1. Avis sur un programme
    Par FaridM dans le forum Général Java
    Réponses: 4
    Dernier message: 23/10/2009, 22h28
  2. [Turbo Pascal] Votre avis sur un programme (utilisation fichiers)
    Par dourpil dans le forum Turbo Pascal
    Réponses: 1
    Dernier message: 15/10/2009, 09h13
  3. Réponses: 1
    Dernier message: 21/08/2009, 17h17
  4. Votre avis sur mon programme
    Par grinder59 dans le forum Général Dotnet
    Réponses: 0
    Dernier message: 19/09/2008, 11h05
  5. votre avis sur mon programme
    Par warubi dans le forum C++
    Réponses: 6
    Dernier message: 19/02/2007, 09h47

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