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 :

Obtenir la pile d'appels en cours d'exécution


Sujet :

C++

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    159
    Détails du profil
    Informations personnelles :
    Localisation : France, Moselle (Lorraine)

    Informations forums :
    Inscription : Mai 2007
    Messages : 159
    Points : 119
    Points
    119
    Par défaut Obtenir la pile d'appels en cours d'exécution
    Bonjour,

    Je suis sous QTCreator 4.7.2 / QT5.10.0 MinGW32 sous Seven.
    Tout d'abord désolé si je ne suis pas au bon endroit du forum, mais compte tenu du sujet, je pense que c'est le moins mauvais emplacement pour le poser (lié à la fois à C++11 et QTCreator).
    J'ai actuellement un souci d'exception ayant lieu avant le démarrage du programme, (_M_Construct : null not valid), que je n'arrive pas à situer, et qui ne se laisse pas tracer dans le debugger.
    La seule solution que je vois actuellement est de modifier basic_string.tcc pour y ajouter un affichage de la pile d'appels au moment où il lance cette exception (j'en ai exactement repéré l'emplacement).
    Cependant je ne trouve pas comment faire pour afficher cette trace. Quelqu'un connaitrait-il une fonction capable de réaliser cela?

    Par avance merci, et encore une fois désolé si mon sujet est mal placé. Toute remarque ou suggestion sera acceptée.
    A bientôt,
    Marc

  2. #2
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    739
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 739
    Points : 3 627
    Points
    3 627
    Par défaut
    Pour commencer, utilises-tu des variables globales ? Parce si le main n'est pas encore lancé, c'est forcement une globale qui initialise n'importe comment un std::string.

  3. #3
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Salut,

    Pour continuer :

    A priori, _M_Construct : null not valid est le genre de message lorsqu'une exception est lancée (par l'un des constructeur de std::string, que tu construis n'importe comment, comme l'a si bien fait remarquer jo_link)

    Le problème, c'est que, sans voir ton code, il nous sera particulièrement difficile de t'aider. L'idéal serait donc que tu nous montre ton code pour que l'on puisse voir un peu "où tu te plante".

    Mais, si ton code est particulièrement important, tu peux envisager de te limiter aux seules parties qui contiennent des variables globales, car ce sont les seules qui peuvent faire planter l'application avant même qu'elle n'aie démarrer.

    Et, sinon, tu peux envisager de fournir le code sur un serveur git (github ou framagit(*) ) en te disant que, de toutes façons, ce ne sera surement pas perdu: un projet est forcément quelque chose de "vivant", qui évolue (toujours vers une complexité plus importante) au fil du temps, et que "tôt ou tard", tu essayera d'apporter une modification qui risque de "tout casser".

    Git étant un outil de gestion de versions concurrentes, c'est l'outil idéal pour te permettre de "revenir en arrière" (et donc pour annuler une modification malheureuse) quand le besoin s'en fait sentir

    L'un dans l'autre, tout projet qui n'est pas destiné à être "jeté" dés qu'on a vu que cela fonctionne devrait systématiquement être placé sous le contrôle d'un tel outil, tout comme il devrait contenir des tests unitaire, pour s'offrir une chance de garantir la "meilleur qualité possible" au projet
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  4. #4
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    159
    Détails du profil
    Informations personnelles :
    Localisation : France, Moselle (Lorraine)

    Informations forums :
    Inscription : Mai 2007
    Messages : 159
    Points : 119
    Points
    119
    Par défaut
    Merci pour ta réponse. Joli_link_noir.
    Tu as sans doute raison, même à coup sur je dirais.
    Cela dit, j'ai été incapable de la trouver dans la centaine de fichiers et de classes qui font actuellement partie de mon projet (recherches globales et tout).
    Les seuls mots clé static que je trouve sont soit dans des fonctions soit pour en déclarer (ou alors il est passé au travers de mes recherches). Et aucun ne déclare de string... Même pas léopard... Bon, je sors...
    C'est pourquoi je pose cette question. Cela dit, dans les forums que j'ai visité il y en a un qui parlait d'un sysinfo.h avec une fonction dont je ne me souviens pas du nom mais manifestement ni le fichier ni la fonction ne sont plus référencées (le post date de 2006 tu me diras). Raison de mon petit espoir d'obtenir une réponse ici.

    Encore merci, et à bientôt,
    Marc

  5. #5
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    159
    Détails du profil
    Informations personnelles :
    Localisation : France, Moselle (Lorraine)

    Informations forums :
    Inscription : Mai 2007
    Messages : 159
    Points : 119
    Points
    119
    Par défaut
    Merci aussi Koala01 pour ta réponse.
    Je suis bien conscient de tout cela, et en effet il semble que c'est ce à quoi je suis condamné...
    Mon projet est sous svn, et je peux effectivement faire un retour. Cela dit j'ai fait une petite erreur, en enregistrant un bond un peu trop important, du coup je vais devoir reprendre beaucoup de boulot...
    En plus, c'est un ancien projet (plus de 20 ans, écrit en C++Builder4) que je reprends, que je veux améliorer et dont je ne maitrise plus parfaitement tous les secrets :p . Cela dit aujourd'hui il fonctionne encore dans son ancienne version.
    Le fait est que là je suis à la recherche d'une solution moins coûteuse, et partager mon code ne serait sans doute pas une bonne idée, car si pour moi cela correspond déjà à chercher une épingle dans une meule de foin, je suppose que ce serait bien pire pour vous... Donc s'il pouvait être possible de placer un piège dans _M_Construct, ce serait idéal...
    J'ai également lu qu'on pouvait debugger des exécutables. Cela pourrait peut être contourner le démarrage au main. Technique envisageable? Si oui comment fait-on?
    Encore merci
    A bientôt!
    Marc

  6. #6
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 963
    Points
    32 963
    Billets dans le blog
    4
    Par défaut
    Si ça crash avant le lancement du programme, tu n'as pas de stack.
    Sous VS ces crashs sont totalement gérés et visibles dans le debugger. Qt Creator et Mingw ne savent pas les afficher ?
    Sinon tu peux essayer de supprimer le constructeur dans basic_string.tcc et voir où la compil' plante, mais je trouve étrange que ce constructeur puisse échouer.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  7. #7
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    159
    Détails du profil
    Informations personnelles :
    Localisation : France, Moselle (Lorraine)

    Informations forums :
    Inscription : Mai 2007
    Messages : 159
    Points : 119
    Points
    119
    Par défaut
    Merci Bousk
    En fait le message indique que j'ai du passer un char * nullptr sans doute. Je ne sais pas trop où et c'est bien là le problème, d'autant que cet argument peut très bien résulter d'un calcul...
    Néanmoins, ton idée d'abimer ce constructeur me plait.
    Je vais la mettre en oeuvre. Enfin pas ce soir, je dois un peu dormir encore cette nuit...

    Merci à toi
    Et à bientôt!

  8. #8
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Citation Envoyé par Teaniel Voir le message
    Merci aussi Koala01 pour ta réponse.
    Je suis bien conscient de tout cela, et en effet il semble que c'est ce à quoi je suis condamné...
    Mon projet est sous svn, et je peux effectivement faire un retour. Cela dit j'ai fait une petite erreur, en enregistrant un bond un peu trop important, du coup je vais devoir reprendre beaucoup de boulot...
    Oh, je parle de git parce que c'est le système qui a le "vent en poupe"...
    Un lien svn est tout aussi utile qu'un lien git pour nous
    En plus, c'est un ancien projet (plus de 20 ans, écrit en C++Builder4) que je reprends, que je veux améliorer et dont je ne maitrise plus parfaitement tous les secrets :p . Cela dit aujourd'hui il fonctionne encore dans son ancienne version.
    Oufff...
    oui, évidemment...
    Le fait est que là je suis à la recherche d'une solution moins coûteuse,
    Cela peut effectivement se comprendre!

    Sur ce point, Qt semble être le remplaçant idéal

    Cependant, si ton projet a été développé selon les "canons de l'époque", le passage de l'un à l'autre risque de ne pas se faire sans mal : je ne serais pas particulièrement étonné si "l'imprégnation" de la VCL était "maximale" dans ton projet. Me trompés-je

    A tel point que je me demande si une réécriture complète pure et simple ne devrait pas être envisagée, ne serait-ce que comme une certaine manière d'abandonner les dettes techniques que tout projet "antédéluvien" traine généralement derrière lui comme des boulets.

    Car l'alternative qui (pourrait) consiste(r) à commencer par réduire l'imprégnation de la VCL pour en limiter son usage à la seule IHM de ton projet ne prendrait sans doute pas moins de temps (en plus de rendre l'idée d'un refactoring supplémentaire pour réduire les dettes techniques beaucoup plus compliquée à mettre en oeuvre)

    Enfin, il va de soi que c'est toi qui décide, hein
    et partager mon code ne serait sans doute pas une bonne idée, car si pour moi cela correspond déjà à chercher une épingle dans une meule de foin, je suppose que ce serait bien pire pour vous...
    Oh, je ne parirais pas trop là dessus, si j'étais toi

    Ne serait-ce que parce que tu connais l'adage : il y a toujours plus dans deux têtes que dans une

    Et puis, pensons positif : à moins -- bien sur -- que ton projet ne soit commercial et toujours en exploitation (ce qui serait une raison largement suffisante pour ne pas souhaiter en dévoiler le code source ), qu'aurais tu à perdre à le mettre sur un serveur (git, SVN, mercurial ou même CVS si tu veux) public et à nous en fournir l'URL, à part ... le temps nécessaire à la manœuvre

    Mais penses aussi au bénéfice que tu pourrais obtenir en le faisant : qui sait, "quelqu'un" pourrait aussi passer justement "par hasard" sur le fichier et trouver l'erreur, ce qui te permettrait de corriger le problème

    Le bénéfice me semble -- pour potentiel qu'il puisse être -- largement supérieur au risque encourru! Qu'en penses tu
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  9. #9
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    159
    Détails du profil
    Informations personnelles :
    Localisation : France, Moselle (Lorraine)

    Informations forums :
    Inscription : Mai 2007
    Messages : 159
    Points : 119
    Points
    119
    Par défaut
    Bonjour à toi Koala01
    (lol y'en a qui dorment encore moins que moi )

    Tu as encore une fois raison sur tous les plans.
    Cela dit, j'ai tout de même fait preuve à l'époque d'une certaine clairvoyance :
    - La partie 'Données' n'est que peu imprégnée de Builder (quelques propriétés à remplacer par leur getter/setter, et les traces de la VCL à retirer), surtout parce que je n'utilise pas de BDD (question pratique car le programme doit rester léger).
    - La partie UI est parfaitement irrécupérable, ne m'a de toutes façons jamais plu, et je vais beaucoup travailler dessus (dès que le reste fonctionnera, ce qui ne saurait tarder ).
    Ce que j'ai basculé dans le nouveau projet est juste la partie données. Une fois cette gestion corrigée, il me restera à re-concevoir l'IU.
    Je 'ai bien sur déjà essayé de réécrire complètement 'from scratch', mais je suis trop imprégné du modèle que j'avais choisi, et je n'arrive jamais à un truc réellement fonctionnel. Du coup je me suis dit qu'il serait plus simple de partir de ce qui existe. Mon objectif est ici simplement de le faire fonctionner, et ensuite de le faire évoluer.
    Je vais voir pour le mettre sur un serveur Git ou autre pour le partager. Cela dit, je n'ai jamais fait cela, et il va me falloir un petit temps.
    En fait, je cais plutôt le mettre en PJ dans un 7z. Voici le lien Orientation.7z.
    J'espère que vous serez indulgents, presque tous mes choix étaient déjà discutables à l'époque. En particulier il y a un peu trop d'interdépendances entre les modules (raison pour laquelle je n'arrive pas vraiment à tester séparément).
    De plus, comme c'était du code qui n'était pas destiné à être partagé, il est assez peu commenté. Je ne suis qu'un simple amateur, sans aucune prétention par rapport à la qualité de son code (raison supplémentaire de ma réticence à partager)...

    Sur ce point, Qt semble être le remplaçant idéal
    lol Pas photo. J'ai évidemment commencé par là. Au bout d'une heure de travail le compilo m'a sorti une erreur interne sans autre référence. Impossible de savoir quoi changer. Ca semblait lié aux template. En désespoir de cause, j'ai commencé le portage, et évidemment rien de tel ne s'est produit avec Mingw32/QtCreator. En plus, autant à l'époque j'étais fan de Borland, autant maintenant ce GUI me déçoit (enfin bon, c'est pas le propos).
    Voila
    .
    Encore merci, bon courage
    Et à bientôt,
    Marc

  10. #10
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 275
    Points : 10 985
    Points
    10 985
    Par défaut
    C'est clairement une std::string construite à partir d'un 0/nullptr/NULL

    Regarde à utiliser l'address sanaitizer de clang. Il est parfait pour avoir la pile d'appel au moment du crash. Ceci dit, c'est bizarre que gcc ne puisse pas te la donner -- après il faut dire que je fuis mingw, il n'est pas impossible que le portage de gcc/gdb y soit bancal.

    N'hésite pas à utiliser d'autres environnements (VC++ sous windows, gcc/clang sous unix)

    EDIT: Détail, si tu catches toutes les exceptions, tu vas perdre ta pile d'appel et donc tout contexte côté debugger (ou pourquoi les exceptions de logique c'est le mal...). Regarde à la place si tu ne peux pas demander à ton debugger de s'arrêter aux exceptions. Ils en sont capables, mais il faut leur dire.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  11. #11
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 069
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 069
    Points : 12 113
    Points
    12 113
    Par défaut
    En plus des remarques pleines de pertinence de mes VDD, et malgré le fait que je n'utilise jamais (plus) mingw, j'ai quelques remarques.

    Sur les conneries les plus évidentes, le compilateur est ton meilleur ami, et il faut lire TRÈS attentivement les warning qu'il remonte ET aussi le configurer pour qu'il remonte le plus de warning possible.

    L'erreur est potentiellement dans ces warning.

    Si vous compilez avec les informations de débugging ("-g" pour GCC, etc...), un débogueur, qu'il soit "en ligne" ou post-mortem, sera capable d'indiquer la ligne de code du problème (même si c'est avant le main) ainsi que les valeurs des variables.

    Pour utiliser les débogueurs en post-mortem, configurez votre système pour qu'il génère des "dump" et cas de crash.

  12. #12
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Citation Envoyé par Teaniel Voir le message
    Cela dit, j'ai tout de même fait preuve à l'époque d'une certaine clairvoyance :
    - La partie 'Données' n'est que peu imprégnée de Builder (quelques propriétés à remplacer par leur getter/setter, et les traces de la VCL à retirer), surtout parce que je n'utilise pas de BDD (question pratique car le programme doit rester léger).
    Joliiii!

    Ca facilitera déjà les choses
    Ce que j'ai basculé dans le nouveau projet est juste la partie données. Une fois cette gestion corrigée, il me restera à re-concevoir l'IU.
    Je 'ai bien sur déjà essayé de réécrire complètement 'from scratch', mais je suis trop imprégné du modèle que j'avais choisi, et je n'arrive jamais à un truc réellement fonctionnel. Du coup je me suis dit qu'il serait plus simple de partir de ce qui existe. Mon objectif est ici simplement de le faire fonctionner, et ensuite de le faire évoluer.
    Ce n'est absolument pas exclu, s'il ne reste que "quelques points" où la VCL s'accroche désespérément
    Je vais voir pour le mettre sur un serveur Git ou autre pour le partager. Cela dit, je n'ai jamais fait cela, et il va me falloir un petit temps.
    A vrai dire, c'est "relativement" facile:
    tu télécharge et tu installe git
    • tu crées un compte sur github ou framagit (cf les liens de mon intervention précédante)... Personnellement, je préfère framagit depuis que microsoft a racheté github, mais bon
    • tu crée un repository pour ton projet sur le fournisseur de git que tu as choisi
    • tu lance la console git, pour y introduire les commandes
    • cd <dossier parent de la ou tu veux avoir tes sources> (l'idéal sera peut être de choisir un dossier autre que le dossier qui contient tes sources actuelles )
    • git clone <url indiquée lors de la création du repository>, qui va créer un nouveau dossier (s'il n'existe pas) correspondant au nom que tu aura donné à ton projet
    • tu copie l'ensemble des fichiers que contient ton projet (code sources et ressources éventuelles) dans le dossier créé par git
    • dans la console git:
      • cd <nom du dossier> pour entrer dans le dossier du projet
      • git add --all pour faire connaitre à git tous les fichiers qui existent déjà
      • git commit -m"initial commit (get back original project" qui "validera" les modifications (autrement dit: l'ajout de tous les fichiers) au niveau local
      • git push qui te demandera de t'identifier pour pouvoir envoyer le tout au serveur
    • par sécurité : créer une branche de développement :
      • git branch transit (ou n'importe quel nom de ton choix)
      • git checkout transit pour passer dans la branche créée (pas sur que ce soit obligatoire, mais bon)
    • après modifications (ajout ou modification de fichiers)
      • git status te permet de voir les modifications qui ont été apportées mais qui n'ont pas encore été commitées
      • git commit <noms de fichiers> -m"message explicatif" pour commit "local"
      • git push pour tout envoyer au serveur

    Pour les autres possibilités, faudra que tu te farcisse le tuto ad-hoc

    En fait, je cais plutôt le mettre en PJ dans un 7z. Voici le lien Orientation.7z.
    C'est aussi une possibilité, en attendant mieux

    J'espère que vous serez indulgents, presque tous mes choix étaient déjà discutables à l'époque. En particulier il y a un peu trop d'interdépendances entre les modules (raison pour laquelle je n'arrive pas vraiment à tester séparément).
    Toujours Mais indulgents ne veut pas dire complaisants : on ne laissera pas passer d'erreurs sans te la signaler et te l'expliquer (au besoin)

    De plus, comme c'était du code qui n'était pas destiné à être partagé, il est assez peu commenté.
    Quoi, tu n'est pas au courant
    En dehors des cartouches et d'éventuels commentaires didactiques (pour ceux qui écrivent des cours et des tutos), les commentaires sont à bannir du code... Ca tombe bien, non
    Je ne suis qu'un simple amateur, sans aucune prétention par rapport à la qualité de son code (raison supplémentaire de ma réticence à partager)...
    Nous en sommes bien conscients

    En même temps, ce devrait au contraire être ... une raison de plus pour t'inciter à partager ton code!!!

    Car, c'est en le partageant avec des gens qui ont (ou non) "plus l'habitude que toi" et qui pourront t'indiquer les erreurs que tu apprendra le plus (cela s'appelle "la revue par les pairs")
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  13. #13
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Je suis très embêté, car tu as oublié de rajouter le fichier date.h (et donc, sans doute aussi le fichier date.cpp) dans ton archive, ce qui fait se vautrer le compilateur

    Quelques notes au passage:

    1- Evite définitivement les macros, car ils posent plus de problèmes qu'ils n'apportent de réelles solutions ==> Why macros are evil<== (n'hésite pas à suivre les liens #1, #2, #3 et #4

    2- Sois attentif, lorsque tu n'utilises pas les accolades pour englober les blocs d'instructions, à respecter scrupuleusement l'indentation!

    Un code tel que
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
        if (champ.EstValide())
        	return suivant->Evaluer(*champ,args);
     
            const TBaseTable &table=TBaseOrientation::Base()->Table(Type());
            const TEnregistrement &enreg=table[champ];
            return suivant->Evaluer(enreg,args);
    laisse vraiment planer un doute affreux sur tes intentions, car
    • les règles du C++ veulent que seule la ligne suivant-Evaluer(*champs, args);
    • l'indentation laisse à supposer que tu pourrais t'attendre à ce que les quatre lignes soient soumises à la condition

    (une chance que la première ligne impliquée contient une instruction return, qui lève tout à fait le doute quant à tes intentions )

    3- Typiquement, les classes qui interviennent dans une hiérarchie de classes (qui servent soit de classe de base dans un héritage, ou qui héritent d'une classe de base) sont des classes qui ont sémantique d'entité:

    -La comparaison entre deux instances différente de la même classe n'a pas de sens : tu peux comparer (certains de) leurs états séparément, mais chaque instances est -- par nature -- strictement unique
    -La copie n'a absolument aucun sens, le clonage n'en a que très rarement (et je serais d'avis que le clonage de tes classe n'a aucun sens dans le cas des classes que tu as créées)

    4- on trouve des new, des new[], des delete et des delete[] dans plusieurs fichiers... C'est une très mauvaise idée!!! que penserais tu d'utiliser std::unique_ptr ou std::shared_ptr (avec une nette préférence pour le premier)

    5- l'usage du transtypage (dynamic_cast en particulier) est généralement le symptôme par excellence que l'on est passé "à coté de quelque chose":

    Si on l'utilise sous forme de test, cela signifie surement que l'on a été "assez bête" que pour perdre le type réel de la donnée "en cours de route"

    Si on l'utilise de manière "inconditionnelle", cela implique sans doute que l'on utilise un type inadapté pour maintenir le lien vers une donnée particulère

    Quoi qu'il en soit, il y a moyen de faire bien plus simple, sécurisant et, sans doute, bien plus efficace

    Et il y aurait encore bien d'autres remarques à faire, mais je vais déjà te laisser digérer celles là
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  14. #14
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    159
    Détails du profil
    Informations personnelles :
    Localisation : France, Moselle (Lorraine)

    Informations forums :
    Inscription : Mai 2007
    Messages : 159
    Points : 119
    Points
    119
    Par défaut
    Re

    Ben... J'ai envie de dire merci pour le cours, et toutes les autres infos je mets tout ça tout de suite en pratique.

    @Luc : AdressSanitizer -> J'ai vite fait un tour sur le net, ça a l'air prometteur. Pourrait bien être la réponse directe à ma question initiale. Merci!

    @bacelar : Comme je suis sous QT Creator, j'ai des kits de compilation préréglés. Cependant je vérifierai ces réglages, car c'est vrai que le mode de debug n'est pas très bavard... Concernant les warning, j'applique déjà ta maxime. Et je résous tous les warnings quand c'est possible (mon projet compile actuellement avec un seul warning concernant un break manquant dans un switch/case, que je ne mettrai pas) Cela dit je vérifierai également de ce côté là.

    @Koala01 : Merci pour tes encouragements! et je passerai mon code sur Git aussitôt que possible (ce soir donc). Ça m'obligera en même temps à le nettoyer un peu mieux que ce que j'ai fait (il est vrai à grande vitesse avant de partir au boulot ce matin) avec le zip. Génial ce tuto! me permettra de démarrer et même un peu plus! J'indiquerai le lien un peu plus tard.

    Merci à tous,
    et à bientôt!
    Marc

  15. #15
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    159
    Détails du profil
    Informations personnelles :
    Localisation : France, Moselle (Lorraine)

    Informations forums :
    Inscription : Mai 2007
    Messages : 159
    Points : 119
    Points
    119
    Par défaut
    @Koala01
    Désolé, nous avons à nouveau écrit en même temps

    Je suis très embêté, car tu as oublié de rajouter le fichier date.h (et donc, sans doute aussi le fichier date.cpp) dans ton archive, ce qui fait se vautrer le compilateur
    Oups!
    En fait il s'agît de la bibliothèque date.h de Howard Hinnant, qui complète <chrono> avec des fonctions de stream etc... Il n'y a qu'un seul et unique fichier (note qu'il a demandé un passage de son travail au standard, le lien pointe sur sa description). C'est assez impressionnant comme elle m'a permis de réduire le code lié au temps. En pj le contenu du dossier d'install (il a une deuxième bibliothèque pour la gestion des timezones)date-master.7z. ¨Pour ma part je l'ai mis à part près des include de QTCreator.

    1- Evite définitivement les macros
    J'en ai bien conscience. Pour l'instant j'en garderai une grande partie (pour l'instant seulement bien sur) car elles m'ont permis de diviser la taille de mon code par 5 ou 6 à une époque où il n'y avait que très peu de template possibles. A terme, tout le code en macro sera remplacé par des template quand ce sera possible, sinon réorganisé. A l'époque, le maître mot en programmation était 'Encapsulation'. C'est pourquoi j'aimais bien le concept de propriétés de BCB (on accède à une propriété avec '.' et les getter / setter sont cachés, ce qui permet de les remplacer par un accès direct ou un autre calcul sans changer la syntaxe). Et flemmard que je suis, je trouvais plus joli d'écrire objet.champs.champs.champs, plutôt que objet.getChamps().getChamps().getChamps().

    2- Sois attentif, lorsque tu n'utilises pas les accolades pour englober les blocs d'instructions, à respecter scrupuleusement l'indentation!
    C'est normalement ce que je fais, mais les éditeurs mettent parfois des tab où je veux indenter (plusieurs versions de bcb sont passées par là, pas toujours configurées pareil), et comme j'utilise un pas de 4 normalement, ça peut fausser le jeu. Désolé si c'est le cas ici (il y en avait beaucoup que j'ai déjà corrigé. il doit surement en rester un peu). Je le fais d'autant que je trouve moche un code indenté de travers, en plus des erreurs de lecture que ça peut engendrer.

    3- Typiquement, les classes qui interviennent dans une hiérarchie de classes (qui servent soit de classe de base dans un héritage, ou qui héritent d'une classe de base) sont des classes qui ont sémantique d'entité
    Et c'est là que commence la vraie refonte de mon (vieux) code. Dans la mesure où, tel que, il a fonctionné (et fonctionne toujours), je pense assumer ces incohérences pour l'instant et y travailler ensuite. Possible que j'aie tort, mais j'ai le sentiment qu'il me sera plus facile de corriger un code que je sais fonctionner (en gros une chose à la fois).

    4- on trouve des new, des new[], des delete et des delete[] dans plusieurs fichiers... C'est une très mauvaise idée!!! que penserais tu d'utiliser std::unique_ptr ou std::shared_ptr (avec une nette préférence pour le premier)
    Noté. Petit détail : ces concepts n'existaient tout simplement pas à l'époque (apparus avec c++03 et boost de mémoire). Donc cela fera partie de la refonte à venir.

    5- l'usage du transtypage (dynamic_cast en particulier) est généralement le symptôme par excellence que l'on est passé "à coté de quelque chose":
    Tu as surement raison, et je vais évidemment suivre ton conseil.
    Cela dit, je devrai sans doute refaire appel à ce forum le moment venu, car même pour l'instant je ne suis pas sur de savoir comment corriger cela.

    Et il y aurait encore bien d'autres remarques à faire, mais je vais déjà te laisser digérer celles là
    Je te remercie! lol je me disais bien que tout ça ne serait pas gratuit!
    Va me falloir du temps. Comme tu peux le constater, il y a des choses que je sais déjà, d'autres que je découvre.
    Beaucoup de lecture et d'études en perspectives.



    Tu as toute ma reconnaissance pour le travail que tu fais pour moi. C'est vraiment très sympa!
    J'espère pouvoir un jour te rendre la pareille!
    Merci à toi, et aux autres aussi.

    A bientôt,
    Marc

  16. #16
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Citation Envoyé par Teaniel Voir le message
    Oups!
    En fait il s'agît de la bibliothèque date.h de Howard Hinnant, qui complète <chrono> avec des fonctions de stream etc... Il n'y a qu'un seul et unique fichier (note qu'il a demandé un passage de son travail au standard, le lien pointe sur sa description). C'est assez impressionnant comme elle m'a permis de réduire le code lié au temps. En pj le contenu du dossier d'install (il a une deuxième bibliothèque pour la gestion des timezones)date-master.7z. ¨Pour ma part je l'ai mis à part près des include de QTCreator.
    Du coup, ca compile tout de suite beaucoup mieux
    J'en ai bien conscience. Pour l'instant j'en garderai une grande partie <snip>

    Et c'est là que commence la vraie refonte de mon (vieux) code. Dans la mesure où, tel que, il a fonctionné (et fonctionne toujours), je pense assumer ces incohérences pour l'instant et y travailler ensuite. Possible que j'aie tort, mais j'ai le sentiment qu'il me sera plus facile de corriger un code que je sais fonctionner (en gros une chose à la fois).

    ces concepts n'existaient tout simplement pas à l'époque (apparus avec c++03 et boost de mémoire). Donc cela fera partie de la refonte à venir.
    Je comprends parfaitement ton point de vue, ne va surtout pas croire le contraire

    Mais, je crois, sincèrement que, en l'occurrence, tu as tord sur ce coup là.

    Tu veux -- et c'est bien normal -- moderniser un projet qui a fonctionné pendant des années. Mais je crois que, au point où tu en es, tu vas perdre beaucoup plus de temps (et de cheveux !!!) à vouloir corriger les choses les unes après les autres en te disant "ca, je vais laisser sur le coté pour la suite".

    Ne serait-ce que, parce que si j'ai bien compris l'idée de ce projet, c'était de disposer d'une "sorte de base de donnée perso". Et cela peut se comprendre quand on sait à quels choix nous étions contraints à l'époque : entre access et les SGBDR "classiques" (allant de MySQL à Oracle, en passant par MsSql), cela aurait pu te donner l'impression d'avoir à choisir entre la peste et le choléra

    Mais, sais tu que Sqlite, par exemple, fournit désormais un système de base de données particulièrement cohérent, léger, gratuit, opensources et que Qt fournit très gracieusement "tout ce qu'il faut" pour pouvoir manipuler ce genre de base de données "à son aise" (pour information : c'est le système de base de donnée qui se cache derrière Thunderbird )

    De plus, j'ai l'impression que tu t'es beaucoup trop enfoncé dans une approche "tout oo", bien que je comprenne les raisons qui t'ont poussé à agir de la sorte, je crois que le fait d'élargir directement tes horizons pourrait te faciliter énormément la vie.

    Par exemple, tout ton dossier CHAMPS pourrait allègrement se résumer à quelque chose qui serait proche de
    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
     
    /*désolé, mais j'ai trop l'habitude de prendre des noms anglais */
    template <typename T, bool Convertible>
    struct Strignifier;
    /* il y aura quelques spécialisations (pour std::string, notamment) à ajouter par la suite ;) */
    template <typename T,
    struct Strignifier<T, true>{
        std::string std::string toString(T const & v) const{
            return std::to_string(v);
        } 
    };
    template <typename Type, bool StringConvertible = std::is_arithmetic_v<Type> || 
                                            std::is_same_v<std::string, Type> || 
                                            std::is_same_v<std::wstring, Type>>
    struct Field{
        using strignifier_type = Stringifier<Type, StringConvertible>;
        Field(std::string const & n):name{n}{
        }
        std::string const name;
        Type value; 
    };
    template <typename T>
    inline bool sameName(Fied<T> const & f, std::string const & name){
        return f.name == name;
    }
    template <typename T, typename U,
                  typename = std::enable_if<std::is_same_v <T, U>::type>
    bool operator = (Field <T> const & f, U const & test){
        return f.value == test;
    }
    pour les enregistrement, nous pourrions avoir recours au CRTP sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    template <typename T>
    struct RecordBase{
       Field< IdType > id{"Id"};
    };
    template <typename Fields>
    struct Record : public RecordBase<Fields>, public Fields{
    };
    Ce qui nous permettrait de définir un enregistrement sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    struct AddressFields{
        Field<std::string> street{"Street"};
        Field<int>  number{"Number"};
        Field<std::string> zipCode{"ZipCode"};
        Field<std::string> locality{"Locality"};
        Field<std::string> town{"Town"};
    };
    using AddressRecord = Record<AddressFields>;
    Dis toi bien que, à partir du moment où tu passe ton temps à jouer avec des accesseurs et des mutateurs, il n'y a plus aucune raison de s'amuser à placer les données dans l'accessibilité privée: nous sommes avons tout aussi vite fait (en réalité, nous avons beaucoup plus vite fait ) de les garder dans l'accessibilité publique, quitte à s'arranger pour rendre le type totalement opaque pour l'utilisateur, et à lui fournir une série de fonctions qui permettront d'éviter au mieux les problèmes. Je t'expliquerai "plus tard" comment t'y prendre, si tu en émet le souhait

    Et, à partir de là, tu pourrais même créer une classe template sous une forme proche de
    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
    template <typename Rec>
    class Table{
        using set_t =std::set<Rec, [&](Rec const & a, Rec const & b){return a.id<b.id;}>;
    public:
        Table(std::string const & name):name_{name}{
        }
        size_t size() const{
            return records_.size();
        }
        void add(Rec const & r){
            records_.insert(r);
        }
        /* ... */
    private:
        set_t records_;
    }
    Et, tout ce qu'il te faudra pour créer toutes les tables que tu veux se limitera à:
    • une struture que tu définis toi meme pour représenter un enregistrement dans la table et
    • un alias de type sur la spécialisation de Table pour le type d'enregistrement en question.

    En 53 lignes de code, je viens de te permettre de virer une grosse partie des 32 fichiers qui se trouvent dans le dossier CHAMPS et de limiter très sérieusement le code des fichiers qui se trouvent dans les dossier Enregistrements et TABLE

    Alors, bien sur, il manque pas mal de truc! Mais ne crois tu pas que cela vaudrait effectivement la peine de partir d'une feuille blanche

    (au passage, voici un petit projet qui pourrait t'être bien utile dans l'approche DOD )
    WARNING
    Le code présenté ici a été écrit "à la volée" et n'a donc absolument pas été testé (honte à moi )

    Si je ne me suis pas trompé, il devrait fonctionner. Mais il se peut tout aussi bien qu'il ne compile même pas sans certaines modifications
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  17. #17
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 069
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 069
    Points : 12 113
    Points
    12 113
    Par défaut
    En plus des conseils plein de claire-voyance de @koala01, il est aussi possible de mettre en place, avec des framework dédiés aux tests, les tests de non-régression qui permettra d'être bien plus confortable pour le refactoring qui s'impose.
    Le fait d'avoir séparé la partie graphique de la partie métier permettra de conserver ces tests même après le passage à Qt comme bibliothèque graphique.

  18. #18
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    159
    Détails du profil
    Informations personnelles :
    Localisation : France, Moselle (Lorraine)

    Informations forums :
    Inscription : Mai 2007
    Messages : 159
    Points : 119
    Points
    119
    Par défaut
    Bonjour,

    @Koala01 : Je suis un peu bluffé par la rapidité de ton analyse. Je pense que tu as surement raison.

    Tu veux -- et c'est bien normal -- moderniser un projet qui a fonctionné pendant des années.
    C'est effectivement mon idée, et j'en comprends également les implications (de mieux en mieux même lol). Cela dit, le temps, tu as dû te rendre compte, je l'ai déjà perdu (Quand à mes cheveux... Plus de risque de ce côté là...). Le code que je t'ai fourni est déjà presque fonctionnel: Il compile complètement et il subsiste simplement (s'il n'en masque pas d'autres) le bug qui a motivé ce post. Ce n'est que dans ce délai que je reporte mon analyse. J'aurais dû le dire plus tôt je m'en rends compte maintenant, mais champs et enregistrements ont été testés individuellement (main() en contient encore le code).
    En fait, il s'agît bien d'une migration, car je souhaite reprendre toutes les données que j'ai conservées depuis ces années, les mettre également au goût du jour (Certaines données en trop, et d'autres à réorganiser).
    Et puis bon, ça me fait aussi plaisir de voir que mon code fonctionne encore avec C++17, presque sans retouche. Je pense même que ce n'est pas loin d'être la raison principale (narcissique vous avez dit?).

    Ne serait-ce que, parce que si j'ai bien compris l'idée de ce projet, c'était de disposer d'une "sorte de base de donnée perso". Et cela peut se comprendre quand on sait à quels choix nous étions contraints à l'époque : entre access et les SGBDR "classiques" (allant de MySQL à Oracle, en passant par MsSql), cela aurait pu te donner l'impression d'avoir à choisir entre la peste et le choléra
    Tu ne crois pas si bien dire.
    Sérieusement, j'ai une raison pratique d'en rester aux fichiers plats : Mes 'clients' et amis qui sont appelés à utiliser ce programme ne sont pas informaticiens. Le programme et le fichier qui l'accompagne (actuellement ça prend cette forme) circulent d'ordinateur en ordinateur, bien souvent sans même quitter la clé, et doivent pouvoir être manipulés hors de ma présence. Tout cela en pleine nature (au bord de plans d'eau pour être précis). Pour l'instant, je conserve cette contrainte forte : Zéro install et le moins de fichiers possibles. Je pense que ça ne laisse pas beaucoup de choix... Les webservices, j'y réfléchirai plus tard.

    De plus, j'ai l'impression que tu t'es beaucoup trop enfoncé dans une approche "tout oo", bien que je comprenne les raisons qui t'ont poussé à agir de la sorte, je crois que le fait d'élargir directement tes horizons pourrait te faciliter énormément la vie.
    Là je me fais juste l'impression d'être un vieux croulant .
    En effet, à cette époque, on ne pensait que oo. Tout était objet, et tous les mécanismes de mon programme y sont soumis. Ce sont des objets qui parlent à d'autres objets. En plus on ne savait pas les factoriser autrement qu'en utilisant des macros. Ça avait également l'avantage de fournir une certaine lisibilité (on peut assez facilement - si c'est bien conçu - connaître les responsabilités de chacun), et j'ai encore de la littérature qui parle de réification, c'est à dire de représentation de la réalité en OO (ça a abouti à UML). A la réflexion, c'est vrai qu'au fil du temps j'ai plus appris à réfléchir Objets que C++ (j'ai aussi utilisé UML pendant un temps)...

    Et, tout ce qu'il te faudra pour créer toutes les tables que tu veux se limitera à:

    une struture que tu définis toi même pour représenter un enregistrement dans la table et
    un alias de type sur la spécialisation de Table pour le type d'enregistrement en question.
    Je prends. Et ton code m'intéresse particulièrement. Merci beaucoup !
    Deux ans de réflexion et de codage (et 8 ou 9 d'entretien) résumés en 65 lignes de code... Vexant tout de même un peu... Heu... 53... Encore pire!
    (:humour: évidemment!)

    Je vous remercie tous pour votre implication!
    Je vais maintenant me concentrer un peu sur la résolution de mon souci du début, tout en pensant aux soucis qui m'attendent...

    A bientôt,
    Marc

  19. #19
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    159
    Détails du profil
    Informations personnelles :
    Localisation : France, Moselle (Lorraine)

    Informations forums :
    Inscription : Mai 2007
    Messages : 159
    Points : 119
    Points
    119
    Par défaut
    Bonjour,

    Je viens de trouver le coupable.
    En fait, c'est un problème que j'ai introduit au moment de la correction d'un des sources (TEnregistrementClassement), qui initialisait plusieurs attributs de type TChampsCalcule avec nullptr (c'est moi qui ai interprèté la valeur d'initialisation 0, qui était acceptable, en nullptr, qui l'était beaucoup moins . Je me demùande ce que j'avais bu ce soir là...).
    Ce que j'ai du mal à comprendre, c'est que aucun constructeur de la classe TChampsCalcule n'accepte un pointeur comme seul argument. J'aurais dû me faire insulter par le compilateur.
    Pour arriver à ce résultat, j'ai simplement changé de version de MinGW (passé à QT5.12 et le compilo en MinGW 3.7 64b) comme ça j'ai effectivement C++17 et 64b, ce que MinGW 5.3 32 ne me permettait pas. Avec cette version, le point d'arrêt que j'avais placé sur la ligne throw de _M_Construct a fonctionné, et je suis arrivé à mes fins.
    Merci à tous pour vos conseils et votre patience.
    @Koala01 je vais sans doute revenir vers toi concernant le code que tu m'as donné. Actuellement je cherche à le comprendre et je vais peut-être avoir besoin de ton aide pour cela, si tu le veux bien évidemment (le moins qu'on puisse dire est que je ne suis pas familier des classes trait). C'est pourquoi je laisse le sujet ouvert.

    Encore merci
    A bientôt,
    Marc

  20. #20
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Citation Envoyé par Teaniel Voir le message
    Je prends. Et ton code m'intéresse particulièrement. Merci beaucoup !
    Deux ans de réflexion et de codage (et 8 ou 9 d'entretien) résumés en 65 lignes de code... Vexant tout de même un peu... Heu... 53... Encore pire!
    (:humour: évidemment!)
    Y a pas de quoi être vexé!!! Tu sais, je vis C++ depuis plus de quinze ans maintenant, en veillant à me tenir à jour

    Il est donc "dans l'ordre des choses" que je m'y connaisse "un tout petit peu", et que je puisse trouver des solutions auxquelles tu n'aurais sans doute pas pensé

    En outre, j'ai eu mauvaise conscience à te fournir un code si crapuleusement non testé. Je me suis donc amusé à faire quelque chose de correcte. Et, comme je sais que tu utilises QtCreator, j'ai veillé à fournir la gestion du projet sous la forme "native" utilisée par cet EDI

    Je te présente Emrh.zip (pour Easy Multi Record Holder). Il y a encore plein de chose à rajouter pour que cela puisse effectivement devenir utilisable, mais tu devrais avoir beaucoup plus facile à le comprendre
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

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