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 :

Bien quitter son programme


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé Avatar de dafpp
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2008
    Messages
    345
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2008
    Messages : 345
    Par défaut Bien quitter son programme
    Bonjour, quelle est la meilleur manière pour quitter le programme quand il y a une erreur?
    Car oui, parfois, de la mémoire est alloué, mais est seulement désaloué à la fin. Et faire une fonction qui désaloue tous les morceaux m'oblige à mettre les variables qui pointe dessus en global.
    Donc dans ce cas, qu'est ce qu'il faut faire?
    Merci d'avance.

  2. #2
    Membre Expert
    Avatar de skeud
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2011
    Messages
    1 091
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 1 091
    Billets dans le blog
    1
    Par défaut
    Tout dépend, si c'est un programme one-shot (qui effectue un traitement puis s'arrete) ou non.

    Si c'est un one-shot, tu n'as pas trop besoin de t'occuper de libérer la mémoire, elle sera automatiquement libérer lors de l'arret, donc ça règle la question.

    Par contre si ce n'est pas un one-shot, tu dois IMPERATIVEMENT libérer la mémoire au fur et à mesure que tes variable ne servent plus.

    Dans le cas d'un non one-shot:
    Ne jamais utilisé exit(-1); pour quitter le programme, sinon l'utilisateur ne comprendras pas pourquoi il s'est arrété brutalement.
    Préfere dans chaque fonction, un code de retour, qui permet de savoir la bonne exécution ou non de cette partie.
    Perso, ce que je fais, c'est une fonction qui va libérer la mémoire pour tout les objets rendu inutile après le passage de la fonction, elle sera appelé dans le cadre de la réussite ou non, juste avant le return.


    De manière générale, il faut toujours libérer la mémoire au plus proche de la fin d'utilisation d'une variable afin de limiter la consommation de mémoire et les risques de leak.

    En espérant que ma réponse t'as aidé

  3. #3
    Modérateur
    Avatar de gangsoleil
    Homme Profil pro
    Manager / Cyber Sécurité
    Inscrit en
    Mai 2004
    Messages
    10 150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Manager / Cyber Sécurité

    Informations forums :
    Inscription : Mai 2004
    Messages : 10 150
    Par défaut
    Citation Envoyé par skeud Voir le message
    Si c'est un one-shot, tu n'as pas trop besoin de t'occuper de libérer la mémoire, elle sera automatiquement libérer lors de l'arret, donc ça règle la question.
    Non. Tu supposes ici que l'OS fait bien son travail, ce qui n'est pas forcement le cas -- de meme que je suppose que lorsque tu utilises des ressources dans ton programme, tu finiras par les supprimer apres.


    Sinon, je me range a peu pres a ce que dit Sve@r : tu alloues et desalloues au fur et a mesure des besoins.
    "La route est longue, mais le chemin est libre" -- https://framasoft.org/
    Les règles du forum

  4. #4
    Rédacteur
    Avatar de Franck.H
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Janvier 2004
    Messages
    6 951
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2004
    Messages : 6 951
    Par défaut
    +1

    Ne jamais supposer, si tu alloues dynamiquement de la mémoire tu la libère toi-même lorsque tu n'en as plus besoin car le reste est trop dépendant du système. D'ailleurs même lorsque tu libère toi-même la mémoire rien ne garantit que ce soit fait immédiatement et je pense que c'est rarement le cas.
    Mon Site
    Ma bibliothèque de gestion des chaînes de caractères en C

    L'imagination est plus importante que le savoir. A. Einstein

    Je ne répond à aucune question technique par MP, merci d'avance !

  5. #5
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 487
    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 487
    Par défaut
    Citation Envoyé par gangsoleil Voir le message
    Non. Tu supposes ici que l'OS fait bien son travail, ce qui n'est pas forcement le cas -- de meme que je suppose que lorsque tu utilises des ressources dans ton programme, tu finiras par les supprimer apres.
    Merci de le signaler !

    De toutes façons, dès lors que ce programme simple fonctionnera, le primo-postant passera en principe à quelque chose de plus compliqué. Donc autant apprendre dès le départ à faire les choses proprement.

  6. #6
    Membre Expert
    Avatar de imperio
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2010
    Messages
    872
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2010
    Messages : 872
    Par défaut
    Citation Envoyé par skeud Voir le message
    Dans le cas d'un non one-shot:
    Ne jamais utilisé exit(-1); pour quitter le programme, sinon l'utilisateur ne comprendras pas pourquoi il s'est arrété brutalement.
    Je vois pas pourquoi, la fonction atexit existe pour ca, dans la fonction appelee tu peux tres bien faire de l'affichage ou meme gerer la memoire de ton programme si tu l'as centralise (un peu comme tu l'as decrit toi-meme dans ce post :

    Citation Envoyé par skeud
    Perso c'est justement pour ça que j'utilise une fonction qui va s'occuper de la gestion de la memoire:

    Pour chaque traitement j'ai une fonction qui alloue les ressources dans une structure.
    Une deuxieme qui prend cette structure et effectue le traitement.
    Une troisieme qui free tout ce dont je n'ai plus besoin.
    ).

  7. #7
    Membre Expert
    Avatar de skeud
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2011
    Messages
    1 091
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 1 091
    Billets dans le blog
    1
    Par défaut
    Alors, perso, la fonction exit, je préfère l'évitée.
    Oui elle existe, et non c'est pas forcément top.
    Pareil que les goto et autres trucs de ce genre, c'est une bonne pratique de ne les utilisé que lorsqu'il n'y a aucune autres solutions.

    Je disais d'éviter d'utiliser exit dans un programme qui n'est pas en one-shot.Du style un progiciel ou juste un petit soft qui possède une interface graphique.

    Imagine si en cas d'erreur, ton jeux quitte et ferme tout sans rien te dire au lieu de t'afficher une erreur. C'est pour ça que de base, il vaut mieux ne pas utiliser exit.

    Comme précisé plus haut, un programme possède une entrée et une sortie qui est le main et le retour du main.

    EDIT: autant pour moi je n'avais pas vu le "at" devant le exit .
    Bref, perso je suis pas fan, ces fonctions sont utiles pour coder rapidemment, mais je les aimes pas trop, c'est mieux de gérer exactement la mémoire au plus proche de sont utilisation et non pas lors de la fin du main

  8. #8
    Membre Expert
    Avatar de imperio
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2010
    Messages
    872
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2010
    Messages : 872
    Par défaut
    Le atexit n'est pas une mauvaise pratique, il est tres utile dans le cas de l'utilisation d'une lib externe, par-exemple la SDL. Apres son initialisation, tu peux tres bien utiliser atexit pour appeler SDL_Quit(). Ca t'evite d'avoir a t'en preoccuper plus tard. Donc je le repete, de mon point de vue, exit est bonne chose (mais a utiliser avec intelligence comme tout le reste).

  9. #9
    Rédacteur
    Avatar de Franck.H
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Janvier 2004
    Messages
    6 951
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2004
    Messages : 6 951
    Par défaut
    Pareil pour atexit, je l'utilise pour automatiser des tâches en fin de programme
    Mon Site
    Ma bibliothèque de gestion des chaînes de caractères en C

    L'imagination est plus importante que le savoir. A. Einstein

    Je ne répond à aucune question technique par MP, merci d'avance !

  10. #10
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 026
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 026
    Par défaut
    Citation Envoyé par gangsoleil Voir le message
    Non. Tu supposes ici que l'OS fait bien son travail, ce qui n'est pas forcement le cas -- de meme que je suppose que lorsque tu utilises des ressources dans ton programme, tu finiras par les supprimer apres.
    Pour la mémoire allouée, si vous avez un OS qui ne la libère pas correctement...
    Changez vite d'OS !
    En effet, si dès qu'un programme plante ou a une petite fuite de mémoire, la mémoire n'est pas désallouée par l'OS à la fin du programme...
    Je ne sais pas comment fonctionne la gestion de la mémoire sous Windows, mais sous Linux, il est impossible que la mémoire ne soit pas libérée à la fin du programme. Ce qui n'empêche pas de libérer soit-même la mémoire


    Citation Envoyé par imperio Voir le message
    Le atexit n'est pas une mauvaise pratique, il est tres utile dans le cas de l'utilisation d'une lib externe, par-exemple la SDL. Apres son initialisation, tu peux tres bien utiliser atexit pour appeler SDL_Quit(). Ca t'evite d'avoir a t'en preoccuper plus tard. Donc je le repete, de mon point de vue, exit est bonne chose (mais a utiliser avec intelligence comme tout le reste).
    Personnellement, le seul endroit où j'utilise exit(), ce sont dans les fonctions (bad_)usage() :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    void usage(const char * command)
    {
           fprintf("usage : %s blabla\n", command);
           exit(EXIT_FAILURE);
    }
     
    int main(int argc, char ** argv)
    {
          if( param_pas_valide)
                  usage(argv[0] );
     
          return EXIT_SUCCESS;
    }
    Mais un bibliothèque ne devrait jamais utiliser exit(). C'est à l'utilisateur de décider que faire en cas d'erreurs, il faut dans tous les cas, remonter l'erreur à l'utilisateur.
    C'est aussi à l'utilisateur de décider que faire après qu'il en ai terminé avec la bibliothèque : quitter le programme ? relancer ? se faire recouvrir ?

    Appeler exit() dans une fonction n'a donc pas vraiment de raison d'être. Utiliser atexit() devrait alors être très rare.

    D'ailleurs la SDL déconseille l'utilisation de atexit() :
    Note: L'utilisation de atexit peut être parfaite dans de petits programmes, mais les utilisateurs plus avancés devraient clore la SDL sans son utilisation. De plus, l'utilisation de atexit dans une bibliothèque est une manière sure de provoquer un crash à cause du code chargé dynamiquement.
    .

  11. #11
    Expert confirmé
    Avatar de gerald3d
    Homme Profil pro
    Conducteur de train
    Inscrit en
    Février 2008
    Messages
    2 315
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Conducteur de train
    Secteur : Transports

    Informations forums :
    Inscription : Février 2008
    Messages : 2 315
    Billets dans le blog
    5
    Par défaut
    Citation Envoyé par dafpp Voir le message
    ...Et faire une fonction qui désaloue tous les morceaux m'oblige à mettre les variables qui pointe dessus en global.
    Merci d'avance.
    Si tu te sens obligé de déclarer en global c'est que ton architecture logicielle ne doit pas être bien agencée. Pourrais-tu nous montrer ton code, à moins qu'il soit trop long ?

    Quant à la réponse de "Skeud", tout est dit .

  12. #12
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 839
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 839
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par dafpp Voir le message
    Bonjour, quelle est la meilleur manière pour quitter le programme quand il y a une erreur?
    Salut
    Si tu demandes "la meilleure" tu auras 500 millions de réponses.
    Pour moi, on rentre dans un programme par le main et on en sort par le main. Et donc si une fonction interne bloque pour une raison X ou Y, elle doit se borner à renvoyer l'erreur à l'appelant qui gèrera en conséquence (quitte à lui-aussi arrêter et renvoyer le pb à l'appelant et etc etc jusqu'au main). Donc en fait on ne met jamais de exit() dans une fonction (et on peut même éviter d'en mettre dans le main en remplaçant exit par return, ça marche aussi).

    Citation Envoyé par dafpp Voir le message
    Car oui, parfois, de la mémoire est alloué, mais est seulement désaloué à la fin. Et faire une fonction qui désaloue tous les morceaux m'oblige à mettre les variables qui pointe dessus en global.
    Donc dans ce cas, qu'est ce qu'il faut faire?
    Merci d'avance.
    Tu devrais regarder ma fonction qui recopie stdin dans un char* dans ton topic sur stdin ici car j'y ai intégré une gestion d'erreurs malloc.
    Et donc si à un moment donné le malloc échoue, déjà comme j'ai gardé le pointeur précédent je peux le libérer mais en plus je me contente de renvoyer le pb à l'appelant (le main) qui, lui, gère alors la crise.
    Mais tout n'est toujours pas aussi simple. Prenons par exemple le cas de 3 buffers. Tu feras un premier malloc que tu vas gérer. Puis un second et tu devras alors gérer le cas du second malloc échoué en n'oubliant pas de libérer alors le premier buffer. Puis idem au 3°. Cela donnerait alors un truc de ce genre
    Code c : 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
    void fonction()
    {
        char *buf1;
        char *buf2;
        char *buf3;
     
        buf1=malloc(...)
        if (buf1 == NULL)
            return;
     
        buf2=malloc(...)
        if (buf2 == NULL)
        {
            free(buf1);
            return;
        }
     
        buf3=malloc(...)
        if (buf3 == NULL)
        {
            free(buf1);
            free(buf2);
            return;
        }
     
        .... // travail
        free(buf1);
        free(buf2);
        free(buf3);
    }
    Ca reste lisible et dans une philosophie que j'aime bien (commencer par gérer tous les pb puis ensuite coder le travail réel). Mais ca ne plaira pas à certains puristes qui te parleront de redondance des free() et qui rajouteront qu'une fonction void ne doit pas avoir de return (oui oui, le monde de la prog possède aussi son inquisition et son bûcher). On va donc coder différemment pour contenter ces ayatollistes...
    Code c : 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
    int fonction()
    {
        char *buf1;
        char *buf2;
        char *buf3;
     
        buf1=malloc(...)
        if (buf1 != NULL)
        {
            buf2=malloc(...)
            if (buf2 != NULL)
            {
                buf3=malloc(...)
                if (buf3 != NULL)
                {
                    .... // travail
                    free(buf3);
                }
                free(buf2);
            }
            free(buf1);
        }
    }
    Un code plus pur... mais moins lisible. Et si en plus tu dois gérer 50 ressources, une fois tous les tests faits tu te retrouves à coder complètement à droite de l'écran. Mais ça reste puriste.

    Ensuite, tu peux essayer de ruser (comme le voleur dans le donjon de Naheulbeuk). Ca plait pas au barbare qui a peur de Crôm mais ça marche... surtout quand tu utilises judicieusement une instruction peu usitée de par la polémique qu'elle suscite: le "goto". Personnellement moi je dis que ce ne sont pas les outils qui sont mauvais mais la façon dont on s'en sert. Et donc si on s'en sert judicieusement, un bon "goto" bien placé peut améliorer bien des choses. Voyons donc ce que ça donnerait...

    Code c : 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
    int fonction()
    {
        char *buf1=NULL;
        char *buf2=NULL;
        char *buf3=NULL;
     
        buf1=malloc(...)
        buf2=malloc(...)
        buf3=malloc(...)
        if (buf1 == NULL  || buf2 == NULL || buf3 == NULL)
            goto clean;
     
        .... // travail
     
        // Nettoyage
        clean:
        free(buf1);
        free(buf2);
        free(buf3);
    }
    Ca marche parce que soit le pointeur est alloué par malloc soit il est à NULL et free() sur un pointeur NULL reste sans effet.

    Voilà différentes façon de résoudre un pb simple. Maintenant chaque pb est différent. L'important c'est que tu essayes d'être simple dans ta façon de faire et que tu arrives à te relire. Et pour ça il y a un truc incontournable: le commentaire...

    Citation Envoyé par skeud Voir le message
    Si c'est un one-shot, tu n'as pas trop besoin de t'occuper de libérer la mémoire, elle sera automatiquement libérer lors de l'arret, donc ça règle la question.
    Argh je supporte pas ce genre de phrase. C'est "je m'en fouts je laisse faire les autres". Jusqu'au jour où tu tombes sur un OS pourri où chacun s'est appuyé sur tous les autres et tu es obligé de le rebooter toutes les 25 minutes...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  13. #13
    Membre Expert
    Avatar de skeud
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2011
    Messages
    1 091
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 1 091
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Sve@r Voir le message

    Un code plus pur... mais moins lisible. Et si en plus tu dois gérer 50 ressources, une fois tous les tests faits tu te retrouves à coder complètement à droite de l'écran. Mais ça reste puriste.
    Perso c'est justement pour ça que j'utilise une fonction qui va s'occuper de la gestion de la memoire:

    Pour chaque traitement j'ai une fonction qui alloue les ressources dans une structure.
    Une deuxieme qui prend cette structure et effectue le traitement.
    Une troisieme qui free tout ce dont je n'ai plus besoin.

    C'est peut-être extreme mais au moins j'ai aucun problème de leak, et quand il y en a, c'est hyper facile à resoudre

  14. #14
    Membre éclairé Avatar de dafpp
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2008
    Messages
    345
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2008
    Messages : 345
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    1)
    Code c : 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
    void fonction()
    {
        char *buf1;
        char *buf2;
        char *buf3;
     
        buf1=malloc(...)
        if (buf1 == NULL)
            return;
     
        buf2=malloc(...)
        if (buf2 == NULL)
        {
            free(buf1);
            return;
        }
     
        buf3=malloc(...)
        if (buf3 == NULL)
        {
            free(buf1);
            free(buf2);
            return;
        }
     
        .... // travail
        free(buf1);
        free(buf2);
        free(buf3);
    }
    2)
    Code c : 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
    int fonction()
    {
        char *buf1;
        char *buf2;
        char *buf3;
     
        buf1=malloc(...)
        if (buf1 != NULL)
        {
            buf2=malloc(...)
            if (buf2 != NULL)
            {
                buf3=malloc(...)
                if (buf3 != NULL)
                {
                    .... // travail
                    free(buf3);
                }
                free(buf2);
            }
            free(buf1);
        }
    }
    3)
    Code c : 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
    int fonction()
    {
        char *buf1=NULL;
        char *buf2=NULL;
        char *buf3=NULL;
     
        buf1=malloc(...)
        buf2=malloc(...)
        buf3=malloc(...)
        if (buf1 == NULL  || buf2 == NULL || buf3 == NULL)
            goto clean;
     
        .... // travail
     
        // Nettoyage
        clean:
        free(buf1);
        free(buf2);
        free(buf3);
    }
    Mon problème lors du post, c'est la 1. D'où le fait que je crée un nouveau topic : c'est redondant, et on peut oublier des pointeurs avec de la mémoire allouait.
    Après c'est vrai j'ai pensé à la deuxième, mais c'est lourd au niveau de la lecture du code.
    Moi je suis pour la 3e. C'est la même chose que la deux, mais en plus clair. Car si on voit ça en bas niveau, il y a rien de mal à utiliser goto. (?) Donc j'utilise une variable pour le code retour de mon programme, et je l'utilise au return au final.
    Normalement il n'y a pas de mal si j'utilise dans le main plusieurs fois goto clean?

    C'est toujours un plaisir de poser des questions sur ce site (forum), c'est toujours très instructif. Merci à tous.

    Et je suis sur un très bon OS, je lui fais confiance.

  15. #15
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 839
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 839
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par dafpp Voir le message
    Mon problème lors du post, c'est la 1. D'où le fait que je crée un nouveau topic : c'est redondant, et on peut oublier des pointeurs avec de la mémoire allouait.
    Ben oui. La prog c'est aussi un peu de travail...

    Citation Envoyé par dafpp Voir le message
    Moi je suis pour la 3e. C'est la même chose que la deux, mais en plus clair. Car si on voit ça en bas niveau, il y a rien de mal à utiliser goto. (?)
    Il n'y a rien de mal à utiliser goto à bon escient. Sa mauvaise image vient du basic où il n'y avait que cette instruction qui donnait des programmes difficilements lisibles. Warnier a tenté une méthodologie basée sur cette instruction qui est ce qu'elle est mais bon, maintenant qu'il y a des whiles() et des for()...

    Citation Envoyé par dafpp Voir le message
    Donc j'utilise une variable pour le code retour de mon programme, et je l'utilise au return au final.
    Tu peux utiliser errno qui est là pour ça. Sauf si tu as peur d'une collision (elle est impactée à chaque appel system qui se passe mal)...

    Citation Envoyé par dafpp Voir le message
    Normalement il n'y a pas de mal si j'utilise dans le main plusieurs fois goto clean?
    J'espère que l'étiquette "clean" se trouve elle-aussi dans le main. Alors pas de souci si tu gardes à l'esprit que ce doit être une instruction exceptionnelle réservée à la gestion des erreurs. Maintenant moi j'ai une maxime personnelle pour ce genre de question : un bon programmeur respecte les règles ; un programmeur brillant les transgresse parfois...

    Citation Envoyé par dafpp Voir le message
    ouh! Je profite du topic, en relisant les commentaires, je vois (et c'est pas la première fois bien sûr) que pour tester si un pointeur est NULL, c'est écrit :
    Mais moi je fais toujours
    C'est grave docteur?
    Bah, est-ce que tu as peur de dépasser ton quota ? Sois large, aéré et explicite dans ton code. Au final l'optimiseur donnera le même exécutable mais quel plaisir de se relire facilement. et puis c'est tellement facile de se tromper et d'écrire if (p) au lieu de if (!p) et inversement alors que quand on écrit l'égalité explicite...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  16. #16
    Membre éclairé Avatar de dafpp
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2008
    Messages
    345
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2008
    Messages : 345
    Par défaut
    Bah j'y pensais à errno, mais il y aura des erreurs qui viendront pas d'une histoire de système (comme erreur d'arguments, oublie d'argument, ...).

    Oui le clean se trouve tout à la fin du main, et j'ai retiré tous les exit() venant du main ou ailleurs, et je l'ai remplacé par goto clean;, avec bien sûr le changement de valeur pour la variable de retour.

  17. #17
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 026
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 026
    Par défaut
    Bonjour,

    Pour if(!p) vs if(p == NULL), j'ai deux arguments en faveurs de if(!p) en C++ :
    - c'est plus court à écrire ;
    - on respecte le principe "d'encapsulation" pour les pointeurs "intelligents" :
    ---> On a pas à savoir l'adresse du pointeur ni s'il vaut NULL (nullptr en C++11) ou non. On a juste besoin de savoir s'il est valide ou non (ce qui n'est pas tout à fait la même chose ).

    Ensuite, pour le malloc, attention, sous Linux, par défaut, le malloc ne renverra jamais NULL. En effet l'allocation n'est réellement effectuée qu'à la première utilisation de l'espace alloué.

    Après, pour la libération de la mémoire, plutôt que de faire :
    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
    int fonction()
    {
        char *buf1=NULL;
        char *buf2=NULL;
        char *buf3=NULL;
     
        buf1=malloc(...)
        buf2=malloc(...)
        buf3=malloc(...)
        if (buf1 == NULL  || buf2 == NULL || buf3 == NULL)
            goto clean;
     
        .... // travail
     
        // Nettoyage
        clean:
        free(buf1);
        free(buf2);
        free(buf3);
    }
    On peut aussi faire :
    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
    #define Malloc(Z) ( alloc_it < alloc_max ? ( alloc[alloc_it++] = malloc(Z) ) : NULL )
    #define debutAlloc(SIZE) unsigned int alloc_it = 0; unsigned int alloc_max ; void * alloc[alloc_max = (SIZE)] = {NULL}
    #define finAlloc()  do{ for(int i= 0; i < XX ; ++i) \
               free(alloc[XX]); \
               while(0)
     
    void foo(void)
    {
          debutAlloc(50);
     
          int * toto = (int *)Malloc(sizeof(int) );
          if( ! toto )
          {
                    finAlloc();
                    puts(":cry:");
                    return;
          }
     
          // do some stuff
     
          finAlloc();
    }
    Ce qui pourrait être très pratique si tu as beaucoup d'allocations à faire.
    Les #define pourront être utile si tu veux faire la même chose dans plusieurs fonctions (ou pour frimer )

  18. #18
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 839
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 839
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par dafpp Voir le message
    Bah j'y pensais à errno, mais il y aura des erreurs qui viendront pas d'une histoire de système (comme erreur d'arguments, oublie d'argument, ...).
    Non. Il est impacté par chaque appel système échoué (fopen, malloc, pipe, etc etc etc). Mais c'est conventionnel (chaque fonction a été codée pour le mettre à jour quand elle échoue).
    En revanche, un oubli d'arguments n'est pas un pb système mais un pb humain donc il n'est pas impacté.

    Citation Envoyé par Neckara Voir le message
    Bonjour,

    Pour if(!p) vs if(p == NULL), j'ai deux arguments en faveurs de if(!p) en C++ :
    - c'est plus court à écrire ;
    - on respecte le principe "d'encapsulation" pour les pointeurs "intelligents" :
    ---> On a pas à savoir l'adresse du pointeur ni s'il vaut NULL (nullptr en C++11) ou non. On a juste besoin de savoir s'il est valide ou non (ce qui n'est pas tout à fait la même chose ).
    Ah j'aime pas quand je lis ce genre de truc car je me sens dépassé et ça m'énerve. Bref en quoi "l'encapsulation" fonctionne avec if(!p) et ne fonctionne pas avec if (p == NULL) ? Et quelle différence entre "pointeur invalide" et "pointeur égal à NULL" ? malloc ne renvoie-t-elle pas NULL quand elle échoue ??? Parce que je ne teste pas "pointeur invalide" mais "pointeur égal à la valeur conventionnellement renvoyée par malloc en cas d'échec" ce qui n'est pas tout à fait la même chose dans la notion (même si c'est la même chose dans l'écriture)...

    Citation Envoyé par Neckara Voir le message
    Ensuite, pour le malloc, attention, sous Linux, par défaut, le malloc ne renverra jamais NULL. En effet l'allocation n'est réellement effectuée qu'à la première utilisation de l'espace alloué.
    Et que renvoie-t-elle si elle échoue ??? Parce que le man, lui, parle explicitement de NULL...

    Citation Envoyé par Neckara Voir le message
    On peut aussi faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    #define Malloc(Z) ( alloc_it < alloc_max ? ( alloc[alloc_it++] = malloc(Z) ) : NULL )
    #define debutAlloc(SIZE) unsigned int alloc_it = 0; unsigned int alloc_max ; void * alloc[alloc_max = (SIZE)] = {NULL}
    #define finAlloc()  do{ for(int i= 0; i < XX ; ++i) \
               free(alloc[XX]); \
               while(0)
    Ok, c'est réglé je suis complètement dépassé...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

Discussions similaires

  1. Comment bien déboguer son code ?
    Par D[r]eadLock dans le forum Débuter
    Réponses: 47
    Dernier message: 02/04/2024, 16h06
  2. [JSmooth] Bien intégrer la JRE avec son programme
    Par Ceubex dans le forum EDI et Outils pour Java
    Réponses: 0
    Dernier message: 30/03/2012, 23h01
  3. [mise en page] pour bien indenter son code
    Par bihorece dans le forum C++Builder
    Réponses: 4
    Dernier message: 06/08/2003, 16h14
  4. Mettre son programme dans Envoyer Vers ?
    Par MaTHieU_ dans le forum C++Builder
    Réponses: 11
    Dernier message: 29/07/2003, 19h09
  5. Réponses: 13
    Dernier message: 11/05/2003, 13h25

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