Partage
  • Partager sur Facebook
  • Partager sur Twitter

"Undefined reference to"

Sujet résolu
    13 juillet 2007 à 14:42:08

    Bonjour,

    Lors de la compilation d'un programme, j'obtiens des dizaines d'erreurs type "undefined reference to" à propos des méthodes de mes classes...
    Or j'ai bien implémenté toutes mes méthodes, je soupçonne donc un mauvais makefile, et n'étant pas très à l'aise avec j'aimerais que vous me disiez s'il est correct s'il-vous-plaît :
    CPP=g++
    CXXFLAGS=-Wall -ansi
    EXEC=Test
    LDFLAGS=-Wall -ansi -lSDL -lSDL_image -lSDL_ttf
    SRC=$(wildcard *.cpp)
    OBJ=$(SRC:.cpp=.o)

    all: $(EXEC)

    $(EXEC): $(OBJ)
    @$(CPP) -o $@ $^ $(LDFLAGS)

    %.o: %.cpp
    @$(CPP) -o $@ -c $< $(CXXFLAGS)

    .PHONY: clean mrproper

    clean:
    @rm -rf *.o

    mrproper: clean
    @rm -rf $(EXEC)

    (Les tabulations n'apparaissent visiblement pas, quelles balises utiliser pour colorer un makefile ?)

    Je vous remercie d'avance !
    • Partager sur Facebook
    • Partager sur Twitter
      13 juillet 2007 à 16:38:52

      Qu'est-ce que tu veux qu'on fasse avec un makefile sans code ???
      • Partager sur Facebook
      • Partager sur Twitter
      Co-auteur du cours de C++. ||| Posez vos questions sur le forum ||| Me contacter.
        13 juillet 2007 à 17:58:41

        Et bien je ne vois pas en quoi l'étude de mon makefile nécessite le code... qui prend plusieurs milliers de ligne en une quinzaine de fichiers qui plus est...
        Néanmoins, en voici un morceau :
        CMap.h
        #ifndef STRING
            #define STRING
            #include <string>
        #endif

        #ifndef SDL
            #define SDL
            #include <SDL/SDL.h>
        #endif

        #ifndef CMAP_H
            #define  CMAP_H
           
            #include "Constants.h"
           
            class CSnake;
           
            class CMap
            {
                unsigned short** map;
                CSnake*          snake;
                unsigned short
                    totalColumns,
                    totalLines,
                    level;
                std::string levelsFile;
               
                public:
               
                CMap() : map(NULL), snake (NULL), totalColumns(TOTAL_BLOCKS_WIDTH), totalLines(TOTAL_BLOCKS_HEIGHT), level(0), levelsFile(LEVELS_FILE) {};
                CMap(unsigned short, CSnake*, std::string fileName = LEVELS_FILE);
                ~CMap() {};
               
                void           load(unsigned short);
                void           load(unsigned short, std::string fileName);
                void           findSnake();
                void           save();
               
                unsigned short getTotalColumns() const;
                unsigned short getTotalLines() const;
                Object         getElement(SDL_Rect) const;
                Object         getElement(unsigned short, unsigned short) const;
                unsigned short getLevel() const;
                CSnake*        getSnake() const;
               
                void           set(Object, SDL_Rect);
                void           make(Object);
                //void           refresh();
            };
        #endif
         

        CMap.cpp
        #include <fstream>
        #include <iostream>
        #include <time.h>

        #include "CMap.h"
        #include "CSnake.h"

        using namespace std;

        inline CMap::CMap(unsigned short index, CSnake* newSnake, string fileName) : totalColumns(TOTAL_BLOCKS_WIDTH), totalLines(TOTAL_BLOCKS_HEIGHT), snake(newSnake), levelsFile(fileName)
        {
            load(index);
        }

        inline void CMap::load(unsigned short index)
        {
            load(index, levelsFile);
        }

        void CMap::load(unsigned short index, string fileName)
        {
            ifstream file;
           
            file.open(fileName.c_str(), ios::in);
            if (!file)
            {
                cerr << "Fatal error : unable to load file " << fileName.c_str() << endl;
                bool error;
                throw error;
            }
           
            string line;
            int    i = 0, j = 0;
           
            while (i < index - 1)
            {
                file >> line;
                i++;
            }
           
            i = 0;
            while (i < totalColumns)
            {
                while (j < totalLines)
                {
                    file >> map[i][j];
                    j++;
                }
               
                j = 0;
                i++;
            }
           
            file.close();
           
            findSnake();
           
            level = index;
        }

        void CMap::findSnake()
        {
            unsigned short i = 0, j = 0;
            SDL_Rect       head;
            bool           headFound = false;
           
            while (i < totalColumns)
            {
                while (j < totalLines)
                {
                    if (map[i][j] == SNAKE_HEAD)
                    {
                        if (!headFound)
                        {
                            head.x    = i;
                            head.y    = j;
                            headFound = true;
                        }
                       
                        else
                        {
                            cerr << "Several heads found !" << endl;
                            bool error;
                            throw error;
                        }
                    }
                   
                    j++;
                }
               
                j = 0;
                i++;
            }
           
            SDL_Rect* body = new SDL_Rect[100];
            SDL_Rect  movement;
            Direction previousBody;
           
            i       = 0;
            body[i] = head;
           
            while (true)
            {
                if (previousBody != RIGHT && map[body[i].x + 1][body[i].y] == SNAKE_BODY)
                {
                    body[i + 1].x = body[i].x + 1;
                    body[i + 1].y = body[i].y;
                   
                    if (!i)
                    {
                        movement.x = -1; movement.y = 0;
                        snake->setMovement(movement);
                    }
                   
                    previousBody = LEFT;
                    i++;
                }
               
                else if (previousBody != LEFT && map[body[i].x - 1][body[i].y] == SNAKE_BODY)
                {
                    body[i + 1].x = body[i].x - 1;
                    body[i + 1].y = body[i].y;
                   
                    if (!i)
                    {
                        movement.x = 1; movement.y = 0;
                        snake->setMovement(movement);
                    }
                   
                    previousBody = RIGHT;
                    i++;
                }
               
                else if (previousBody != DOWN && map[body[i].x][body[i].y + 1] == SNAKE_BODY)
                {
                    body[i + 1].x = body[i].x;
                    body[i + 1].y = body[i].y + 1;
                   
                    if (!i)
                    {
                        movement.x = 0; movement.y = 1;
                        snake->setMovement(movement);
                    }
                   
                    previousBody = UP;
                    i++;
                }
               
                else if (previousBody != UP && map[body[i].x][body[i].y - 1] == SNAKE_BODY)
                {
                    body[i + 1].x = body[i].x;
                    body[i + 1].y = body[i].y - 1;
                   
                    if (!i)
                    {
                        movement.x = 0; movement.y = -1;
                        snake->setMovement(movement);
                    }
                   
                    previousBody = DOWN;
                    i++;
                }
               
                else
                {
                    break;
                }
            }
           
            if (!i)
            {
                delete[] body;
                cerr << "Fatal error : no body found !" << endl;
                bool error;
                throw error;
            }

            j = i + 1; i = 0;
            while (i < j)
            {
                snake->lenghten(body[i]);
                i++;
            }

            delete[] body;

            unsigned short k = 1;

            i = j = 0;
            while (i < TOTAL_BLOCKS_WIDTH)
            {
                while (j < TOTAL_BLOCKS_HEIGHT)
                {
                    if (map[i][j] == SNAKE_BODY)
                    {
                        while (k < snake->getSize())
                        {
                            if (i == (snake->getPosition(k).x) && j == (snake->getPosition(k).y))
                            {
                                break;
                            }
                           
                            k++;
                           
                            if (k == snake->getSize())
                            {
                                cerr << "Isolated body found !" << endl;
                                bool error;
                                throw error;
                            }
                        }
                       
                        k = 1;
                    }
                   
                    j++;
                }
               
                j = 0;
                i++;
            }
        }

        void CMap::save()
        {
            if (map)
            {
                ofstream file(levelsFile.c_str(), ios::in|ios::out|ios::app);
               
                int i = 0, j = 0;
                if (!file)
                {
                    file.open(levelsFile.c_str(), ios::out|ios::trunc);
                   
                    while (i < TOTAL_BLOCKS_WIDTH)
                    {
                        while (j < TOTAL_BLOCKS_HEIGHT)
                        {
                            file << "0";
                           
                            j++;
                        }
                       
                        j = 0;
                        i++;
                    }
                   
                    file << endl;
                    file.close();
                }
               
                file.seekp((TOTAL_BLOCKS_WIDTH * TOTAL_BLOCKS_HEIGHT + 2) * (level - 1));
               
                i = j = 0;
                while (j < TOTAL_BLOCKS_HEIGHT)
                {
                    while (i < TOTAL_BLOCKS_WIDTH)
                    {
                        file << map[i][j];
                        i++;
                    }
                   
                    i = 0;
                    j++;
                }
               
                file.close();
            }
           
            else
            {
                cerr << "Warning : no map to save !" << endl;
            }
        }



        inline unsigned short CMap::getTotalColumns() const
        {
            return totalColumns;
        }

        inline unsigned short CMap::getTotalLines() const
        {
            return totalLines;
        }

        inline Object CMap::getElement(SDL_Rect position) const
        {
            return (Object)(map[position.x][position.y]);
        }

        inline Object CMap::getElement(unsigned short x, unsigned short y) const
        {
            return (Object)(map[x][y]);
        }

        inline unsigned short CMap::getLevel() const
        {
            return level;
        }

        inline CSnake* CMap::getSnake() const
        {
            return snake;
        }



        inline void CMap::set(Object object, SDL_Rect position)
        {
            map[position.x][position.y] = object;
        }

        void CMap::make(Object object)
        {
            if (object == APPLE || object == BONUS)
            {
                srand(time(NULL));
               
                SDL_Rect random;
               
                while (map[random.x][random.y] != EMPTY)
                {
                    random.x = rand() % TOTAL_BLOCKS_WIDTH;
                    random.y = rand() % TOTAL_BLOCKS_HEIGHT;
                }
               
                map[random.x][random.y] = object;
            }
           
            else
            {
                cerr << "Warning : CMap::make() received an invalid argument (!= APPLE && != BONUS)" << endl;
            }
        }

        Concernant cette paire de fichier, voilà les erreurs que j'ai :
        CMap.o: In function `CMap::findSnake()':
        CMap.cpp:(.text+0x61f): undefined reference to `CSnake::setMovement(SDL_Rect)'
        CMap.cpp:(.text+0x6e3): undefined reference to `CSnake::setMovement(SDL_Rect)'
        CMap.cpp:(.text+0x7a7): undefined reference to `CSnake::setMovement(SDL_Rect)'
        CMap.cpp:(.text+0x86b): undefined reference to `CSnake::setMovement(SDL_Rect)'
        CMap.cpp:(.text+0x9a8): undefined reference to `CSnake::getPosition(unsigned short) const'
        CMap.cpp:(.text+0x9d7): undefined reference to `CSnake::getPosition(unsigned short) const'
        CMap.cpp:(.text+0xa11): undefined reference to `CSnake::getSize() const'
        CMap.cpp:(.text+0xa7c): undefined reference to `CSnake::getSize() const'

        Et ce pour chacun de mes fichiers .cpp !
        Pour vous convaincre que les fonctions citées ci-dessus sont bien implémentées :
        #include <iostream>

        #include "CMap.h"

        using namespace std;

        inline CSnake::~CSnake()
        {
            if (size)
            {
                delete[] position;
            }
        }



        inline SDL_Rect CSnake::getMovement() const
        {
            return movement;
        }

        inline SDL_Rect CSnake::getPosition(unsigned short index) const
        {
            if (index < size)
            {
                return position[index];
            }
           
            else
            {
                cerr << "Warning : getPosition() received a wrong parameter (index >= size) !" << endl;
                return position[size - 1];
            }
        }

        inline unsigned short CSnake::getSize() const
        {
            return size;
        }

        inline unsigned int CSnake::getScore() const
        {
            return score;
        }

        inline bool CSnake::isAlive() const
        {
            return alive;
        }



        inline void CSnake::setMovement(SDL_Rect newMovement)
        {
            movement = newMovement;
        }

        inline void CSnake::setPosition(unsigned short index, SDL_Rect newPosition)
        {
            if (index < size)
            {
                position[index] = newPosition;
            }
           
            else
            {
                cerr << "Warning : setPosition() received a wrong parameter (index >= size) !" << endl;
            }
        }



        void CSnake::lenghten(SDL_Rect newPosition)
        {
            SDL_Rect *temp = new SDL_Rect[size];

            int i = 0;
            while (i < size - 1)
            {
                temp[i] = position[i];
                i++;
            }

            delete[] position;
           
            size++;
            position = new SDL_Rect[size];

            i = 0;
            while (i < size - 1)
            {
                position[i] = temp[i];
                i++;
            }
            position[size - 1] = newPosition;
        }

        void CSnake::move()
        {
            unsigned int i = size - 1;
            SDL_Rect temp;
           
            temp.x = position[0].x + movement.x;
            temp.y = position[0].y + movement.y;
            if (map->getElement(temp) == WALL)
            {
                die();
            }
           
            else
            {
                while (i)
                {
                    position[i] = position[i - 1];
                    i--;
                }
               
                position[0].x = position[0].x + movement.x;
                position[0].y = position[0].y + movement.y;
               
                i = size - 1;
                while (i)
                {
                    if ((position[i].x == position[0].x) && (position[i].y == position[0].y))
                    {
                        die();
                        break;
                    }
                   
                    i--;
                }
               
                eat();
            }
        }



        void CSnake::eat()
        {
            if (map->getElement(position[0]) == APPLE)
            {
                map->set(EMPTY, position[0]);
                lenghten(position[size - 1]);
                score++;
               
                if (!(score % BONUS_FREQUENCY))
                {
                    map->make(BONUS);
                }
                map->make(APPLE);
            }
           
            else if (map->getElement(position[0]) == BONUS)
            {
                map->set(EMPTY, position[0]);
                score = score + 5;
            }
        }

        inline void CSnake::die()
        {
            if (alive)
            {
                alive = false;
            }
           
            else
            {
                cerr << "Warning : CSnake::die() called while snake already dead !" << endl;
            }
        }
         

        Mais j'ai peut-être donné trop de code me direz-vous...
        • Partager sur Facebook
        • Partager sur Twitter
          13 juillet 2007 à 18:10:31


          // Pas besoin de définir des ifndef, les fichiers inclus le font eux-mêmes
          #include <string>
          #include <SDL/SDL.h>


          #ifndef CMAP_H
          #define  CMAP_H
             
          #include "Constants.h"
          #include "Snake.h"
           
          // Enlève moi ça... c'est normal des undefined reference, le class snake que comprend ton .cpp c'est le premier donc lui
          //class CSnake;
             
          class CMap
              {//...
           


          retire-moi tout les ifndef inutiles et les déclaration de classe vide qui est inutile car tu n'as pas de référence croisée.
          • Partager sur Facebook
          • Partager sur Twitter
            13 juillet 2007 à 18:16:11

            CSnake.h
            #include <SDL/SDL.h>

            #ifndef CSNAKE_H
                #define  CSNAKE_H
               
                class CMap;
               
                class CSnake
                {
                    CMap*          map;
                    unsigned short size;
                    SDL_Rect       *position;
                    SDL_Rect       movement;
                    bool           alive;
                    unsigned int   score;
                   
                    public:
                   
                    CSnake() : map(NULL), size(0), position(NULL), movement(), alive(true), score(0) {};
                    ~CSnake();
                   
                    SDL_Rect       getMovement() const;
                    SDL_Rect       getPosition(unsigned short) const;
                    unsigned short getSize() const;
                    unsigned int   getScore() const;
                    bool           isAlive() const;
                   
                    void           setMovement(SDL_Rect);
                    void           setPosition(unsigned short, SDL_Rect);
                    void           lenghten(SDL_Rect);
                   
                    void           move();
                    void           eat();
                   
                    void           die();
                };
            #endif
             

            La voilà la référence croisée ;)
            D'accord pour les ifndef inutiles !
            • Partager sur Facebook
            • Partager sur Twitter
              13 juillet 2007 à 18:20:04

              alors tu inclus le .h d'un bord et tu fais le class chose; de l'autre

              EDIT:
              http://c.developpez.com/faq/cpp/?page=classes#CLASS_reference_croisee
              • Partager sur Facebook
              • Partager sur Twitter
                13 juillet 2007 à 18:41:14

                J'avais déjà appréhendé le problème des références croisées, mais visiblement c'est la subtilité que tu m'as indiquée qui pose problème :

                Citation

                le class snake que comprend ton .cpp c'est le premier donc lui


                J'ai pourtant suivi le schéma du lien que tu m'as donné :

                CMap.h
                #ifndef CMAP_H
                    #define  CMAP_H
                   
                    #include <string>
                    #include <SDL/SDL.h>
                   
                    #include "Constants.h"
                   
                    class CSnake;
                   
                    // (...)
                 

                CMap.cpp
                #include <fstream>
                #include <iostream>
                #include <time.h>

                #include "CMap.h"
                #include "CSnake.h"

                // (...)
                 

                CSnake.h
                #ifndef CSNAKE_H
                    #define  CSNAKE_H
                   
                    #include <SDL/SDL.h>
                   
                    #include "CMap.h"

                // (...)
                 

                CSnake.cpp
                #include <iostream>

                #include "CSnake.h"

                //  (...)
                 

                Mais je retrouve les mêmes symptômes docteur :euh:

                EDIT : je viens de me rendre compte que le fait que mes fonctions soient inline pose un grand problème, cf ce lien. Il n'y a visiblement pas de solution parfaite, il faut contourner le problème en déclarant les deux classes dans un même en-tête par exemple...
                • Partager sur Facebook
                • Partager sur Twitter

                "Undefined reference to"

                × 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