Partage
  • Partager sur Facebook
  • Partager sur Twitter

LNK2001 : symbole externe non résolu

    25 août 2022 à 10:59:35

    Bonjour,

    Je suis en train d'apprendre les bases de la POO en C++ et j'ai un exercice à faire dans le cadre de cet apprentissage. Le but de l'exercice c'est de faire bouger un petit vaisseau spatial dans une fenêtre et de faire en sorte que quand il sorte de l'écran, il réaparaisse du côté opposé.

    Là j'ai cette erreur : LNK 2001 : symbole externe non résolu pour mes attributs spaceX et spaceY.

    Normalement mes dll sont tous bien installés et il me semble avoir respecté le process pour la déclaration et la définition d'une variable static. Donc je ne comprends vraiment pas mon erreur.

    Le premier screen c'est Coordonnees.h et le deuxième c'est Coordonnees.cpp

    Je précise que les variables lx et ly contiennent les valeurs de 2 constexpr initialisés dans la fonction main. Soit 800 et 600.

    Merci d'avance !

      

    -
    Edité par Jorabgs 25 août 2022 à 11:06:31

    • Partager sur Facebook
    • Partager sur Twitter
      25 août 2022 à 11:33:18

      "LNKxxxx", c'est donc une erreur d'édition de lien.

      Normalement, votre éditeur de lien, les Dll, il s'en cogne, lui, il utilise des .lib ou des .a en fonction de la chaîne de compilation utilisé (en plus des .obj généré par la compilation).

      Pour en revenir à votre "problème", on vois bien la déclaration de spaceX et spaceY dans la .h mais pas leur définition dans le cpp.

      P.S.: postez le code avec le bouton [</>] et pas des copies d'écran, SVP.

      • Partager sur Facebook
      • Partager sur Twitter
      Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
        25 août 2022 à 11:37:49

        Tu as un bouton code  qui ressemble à ça </> pour te permettre d'insérer du code dans le forum. C'est souvent plus lisible et surtout ça nous permet de copier/coller ton code si on veut le tester ou juste en recopier une partie dans notre réponse 

        Pour répondre à ta question, tu n'as pas totalement respecté la façon d'utiliser des variables statiques.

        Les variables statiques sont indépendantes des objets que tu vas créer, elles ne seront donc pas initialisées avec une valeur par défaut (0 pour un int) lors de la création de l'objet. C'est à toi d'indiquer comment les initialiser.

        Au debut de ton fichier Coordonnees.cpp tu dois donc écrire quelque chose comme ça :

        #include <iostream>
        
        #include "Coordonnees.h"
        
        int Coordonnees::spaceX = 0;  // Si tu veux mettre 0 par défaut
        int Coordonnees::spaceY = 0;

        Je ne suis pas sûr qu'initialiser dans le .h tes variables x et y en utilisant tes variables statiques soit possible. Ajoute ce que je t'ai indiqué plus haut et voit si ça marche mais ça serait surement mieux de les initialiser dans ton constructeur 

        Coordonnees::Coordonnees() {
            x = spaceX / 2.f;
            y = spaceY / 2.f;
        }

        Là au moins tu es sûr que que x et y sont initialisées avec des valeurs qui existent, même si tu n'as pas appelé initialiserEspace(), spaceX et spaceY auront été initialisées à 0 dans ton .cpp et x et y vaudront 0 aussi.


        • Partager sur Facebook
        • Partager sur Twitter
          25 août 2022 à 11:55:23

          Ce n'est pas qu'elle ne sont pas initialisées, c'est qu'elle ne sont tout simplement pas défini !

          • Partager sur Facebook
          • Partager sur Twitter
          ...
            25 août 2022 à 13:06:46

            Bonjour, alors d'abord merci pour vos réponses. 

            La prochaine fois j'utiliserai le bouton </> pour montrer mon code, désolé.

            Pour répondre à Bacelar et Rouloude, il me semblait avoir défini spaceX et spaceY dans initialiserEspace ou alors j'ai pas tout compris (désolé je débute donc les notions sont encore assez floues dans ma tête). 

            Du coup j'ai testé la solution que ThibaultVnt m'a proposé et vraiment merci beaucoup ça fonctionne ! Et j'ai laissé les initialisations de x et y dans mon .h pour voir si c'est possible de le faire et il faut croire que oui.

            "Les variables statiques sont indépendantes des objets que tu vas créer, elles ne seront donc pas initialisées avec une valeur par défaut (0 pour un int) lors de la création de l'objet. C'est à toi d'indiquer comment les initialiser."

            Comment ça "comment les initialiser" ? J'ai bien vu l'exemple que tu m'as donné mais j'ai pas trop trop compris.

            Encore merci à tous pour votre aide, j'ai galéré longtemps pour cette erreur. 



            • Partager sur Facebook
            • Partager sur Twitter
              25 août 2022 à 15:40:32

              Je ne suis pas sûr que @ThibaultVnt t'ait bien "conseillé", sans offense.

              Les termes peuvent t'être un peu obscures et un point de détail (et même "nous les experts" on fait des abus de langage) mais sur certains points, les respecter, ça simplifie les choses.

              Il y a trois choses termes à ne pas confondre :

              - déclaration

              - définition

              - initialisation/affectation

              Les déclarations, c'est ce qu'on met dans les .h pour que le compilateur sache de quoi on parle quand on utilise un nom de variable ou de fonction, et cela même quand on compile un .cpp qui n'est pas celui qui contient le code qui définit la variable ou la fonction.

              Ce qui est dans "Coordonnees.h" sont des déclarations qui seront "connues" dans "Coordonnees.cpp" car vous faites un '#include "Coordonnees.h"' au début de "Coordonnees.cpp". Mais vous devez aussi faire un '#include "Coordonnees.h"' dans tous les .cpp (ou les .h mais c'est pas ouf) qui utilisent ce qui est déclaré dans "Coordonnees.h". Le .h peut être inclus dans plusieurs unités de compilation (les .cpp) et cela aura son importance plus tard.

              On peut aussi faire des déclarations dans un .cpp, généralement au début, mais les choses déclarées ne seront connues/utilisables que dans le .cpp où elles sont déclarées (pratique pour des choses à usage interne au code qui est dans le .cpp).

              -

              Les définitions, c'est ce qui est dans le .cpp, comme le corps des fonctions ou les définitions de variables ("int Coordonnees::spaceX;" est une définition de variable, "int Coordonnees::spaceX = 0;" est une définition+initialisation de variable).

              Il y a fort fort longtemps, avec des modèles mémoire des processus bien plus complexes (mémoire swappable ou pas, partageable ou pas, paginable ou pas, etc...), on devait indiquer aux compilateurs directement ou indirectement (via des segments par exemples) où sera réservée l'espace pour ces variables qu'on définit (et pour les plus maso. et les pauvres développeurs de drivers, où sera le code machine des fonctions) dans l'espace d'adressage du processus. C'est le genre de chose qui n'a, actuellement, d'importance que si on développe des librairies statiques ou des dll.

              -

              Les initialisations, c'est juste une première affectation du contenu/la valeur de la variable. C'est toujours bien de les faire pour éviter des trous de sécurité (récupération d'anciennes valeurs,par du code injecté dans le processus, etc...) et des heisenbugs (bugs qui disparaissent quand on essaye de les trouver (par exemple, une compilation en mode DEBUG, involontairement, change souvent la valeur des variables non initialisées)).

              -

              -

              Mais le compilateur, il a pas une case "ça, c'est une déclaration" et une case "ça, c'est une définition", c'est beaucoup plus con.

              Il prend les .cpp un par un, et il doit savoir si le code est valide ou pas, syntaxiquement mais aussi que toutes les variables ou fonctions utilisées seront dans l'exécutable final. Pour ça, il "remplace" les "#include ..." par le contenu de ces fichiers d'en-tête (récursivement). C'est là tout l'intérêt des déclarations. Pas besoin d'avoir le corps de la fonction pour "savoir" qu'elle existera dans l’exécutable.

              C'est fait .cpp par .cpp, et ce qui est connu par la compilation d'un cpp ne l'est pas lors de la compilation d'un autre .cpp.

              -

              En ajoutant "int Coordonnees::spaceX = 0;" dans votre .h, vous avez blousé le compilateur qui l'interprétera comme la définition/initialisation d'une variable (dans le segment .data du processus, c'est le réglage par défaut).

              Le problème se posera dès que vous inclurez "Coordonnees.h" dans un autre .cpp.

              L'éditeur de lien sera face à la définition de 2 variables portant le même nom mais provenant de 2 codes sources différents car provenant de 2 .cpp différents. (les options de fusion de variables dans l'édition de lien, c'est faisable, mais faut pas faire cela pour cacher de grosses erreurs de programmation, SVP.)

              -

              Donc, mettez les définitions dans les .cpp, SVP.

              EDIT:

              J'oubliais aussi :

              >il me semblait avoir défini spaceX et spaceY dans initialiserEspace

              C'est tellement pas la place d'une définition que j'ai même pas lu le corps des fonctions. Et j'espère que mes longues explications te fera comprendre pourquoi.

              Et ton utilisation "candide" des statiques me dit que tu vas te prendre un bon gros "static initialization order fiasco" dans les dents :

              https://en.cppreference.com/w/cpp/language/siof

              -
              Edité par bacelar 25 août 2022 à 16:49:56

              • Partager sur Facebook
              • Partager sur Twitter
              Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                25 août 2022 à 15:44:05

                JorisBorges1 a écrit:

                il me semblait avoir défini spaceX et spaceY dans initialiserEspace ou alors j'ai pas tout compris (désolé je débute donc les notions sont encore assez floues dans ma tête). 

                Heu, non, ça c'est une affectation !

                La définition, c'est le premier code de Thibault.

                La déclaration, c'est les lignes 19 et 20 de ton premier screen shot.

                • Partager sur Facebook
                • Partager sur Twitter
                ...
                  8 septembre 2022 à 11:50:13

                  Merci Bacelar pour ces explications détaillées, ça m'a permis d'éclaircir certains points d'ombre de ces notions.

                  Alors pour le coup Thibault m'a bien conseillé de déclarer spaceX et spaceY dans le .cpp et non dans le .h. 

                  "Il y a fort fort longtemps, avec des modèles mémoire des processus bien plus complexes (mémoire swappable ou pas, partageable ou pas, paginable ou pas, etc...), on devait indiquer aux compilateurs directement ou indirectement (via des segments par exemples) où sera réservée l'espace pour ces variables qu'on définit (et pour les plus maso. et les pauvres développeurs de drivers, où sera le code machine des fonctions) dans l'espace d'adressage du processus. C'est le genre de chose qui n'a, actuellement, d'importance que si on développe des librairies statiques ou des dll."

                  ça n'aurait pas un lien avec l'assembleur ? J'avais eu quelques cours là dessus à la fac avec le 8086. Avec les segments de pile, de data, code etc. C'était une galère. Mais du coup vu que j'utilise mal les static, quels conseils pourriez-vous me donner lors de leur utilisation ? Merci encore pour votre aide !

                  -
                  Edité par Jorabgs 8 septembre 2022 à 11:51:35

                  • Partager sur Facebook
                  • Partager sur Twitter

                  LNK2001 : symbole externe non résolu

                  × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                  × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                  • Editeur
                  • Markdown