Tuesday, April 19, 2011

error LNK2005: "" () already defined in main.obj

Game dev thread
Quick Fix
Full Solution
My Comments

The Problem

What does an error like this mean?

1>Particle.obj : error LNK2005: "struct SDL_Surface * red" (?red@@3PAUSDL_Surface@@A) already defined in main.obj

to put it simply it means that a global variable is defined in two source files because you included the same header file in two different source files.



Lets say I have two source files main.cpp and particle.cpp and a header file called globalobjs.h. In my header file I declare a variable of integer type. Now I need to use this number in both main.cpp and particle.cpp so I'm going to #include "globalobs.h" in both source files. But here is the problem, if I include that globalobjs twice it is like saying the line:
int variable;
twice and so the the linker gives an error message. It is because it doesn't know if I am talking about the same variable or two different variables. It wonders if you want the same variable used in two source files or if you want the two source files to have their own integer called variable. The same logical conclusions would apply for any other type of variable or even functions

In my case here is my Header file called particle.h:

#pragma once
#include 

SDL_Surface *red;
SDL_Surface *green;
SDL_Surface *blue;
SDL_Surface *shimmer;

#ifndef PARTICLE
#define PARTICLE


class Particle
{
protected:
        //offsets
        int x,y;        

        // current frame of animation
        int frame;

        //type of particle
        SDL_Surface* type;

public:
        Particle(int X, int Y);
        ~Particle(void);
        void show();
        bool is_dead();
};

#endif

And here is one of my source files called particles.cpp:

#include "Particle.h"

Particle::Particle(int X, int Y)
{
        x = X + 5 + (rand()%25);
        y = Y + 5 + (rand()%25);

        frame = rand() % 5;

        switch(rand()%3)
        {
        case 0:
                type = red;
                break;
        case 1:
                type = green;
                break;
        case 2:
                type = blue;
                break;
        }
}

As you may have noticed I declared a few pointers red, green, blue which I use to define the member functions of the class I have created in the header file. Those same pointers are again used in the main source file. So now its obvious why i get the message:
1>Particle.obj : error LNK2005: "struct SDL_Surface * red" (?red@@3PAUSDL_Surface@@A) already defined in main.obj
when I try to compile and run my program.

Solution

The way you solve this problem is to explicitly declare variables you want to be globally used as external variables using the keyword etern. A quick reference about the extern keyword can be found here. When you use the word extern it is a way of declaring the variable exists but will be defined a value elsewhere. So now when I include my header file in my source file and declare my pointers as such:
SDL_Surface *red;
The compiler understands that there exists a pointer called red and it may be defined elsewhere.

It is important also to define it elsewhere. That is why in my main.cpp source file I include the particles.h header file and I have the line:
SDL_Surface *red = NULL;
which explicitly defines my pointer. So now I can even call this pointer in another file and it will return the NULL value which I have just assigned.

So to recap:
Declare global variables and functions with the keyword extern in the header file
Define those global variables or functions in one< of the source files


Comments

One more thing I messed up regarding the same topic is to create a global variables header file. Every single declaration needs to be with the keyword extern. Also, For constant terms like:
const int screen_height=1000
declare them as constant static integers.
More over for declarations that don't need to be defined, such as unions, you only need to re-declare them in another source file. For example I say:
SDL_Event event;
in the header file. So in my main.cpp source file i say:
SDL_Event event;

Here is what my completed Global header file looks like:
#include 
#include 
#include 


#ifndef GLOBALFNS
#define GLOBALFNS

//declare some poiters
extern SDL_Surface *dot;
extern SDL_Surface *screen;

extern SDL_Event event;

extern int ScreenW;
extern int ScreenH;

//external functions
extern "C++"{

//The dimensions of the dot
const static int DOT_WIDTH = 20;
const static int DOT_HEIGHT = 20;



//total paticles
const static int TOTAL_PARTICLES = 20;

//SDL supporting functions start
SDL_Surface* loadimg(std::string filename);

void applysurface(int x, int y, SDL_Surface* src, SDL_Surface* dst, SDL_Rect* clop);
}

#endif

1 comment:

  1. Very awesome.
    Thanks to you, I was able to track down the thing that was causing my errors.

    I was making a pac-man game for a uni assignment, when I realised that the way squarish pac-man moves (create player object on tile, then destroy player object... to create player object on an adjacent tile... to simulate movement), that the lives counter I had keeping track IN THE OBJECT CLASS was going to be reset every time it moved!

    *** Ghost to pac-man: "Stand still while I poke you" ***

    To prevent this, I just copy/pasted the variable above the class definition in my player.h file... but NO. I get these weird errors. All I had to do was to write 'static' at the front.
    Thank you.

    ReplyDelete