Page 1 of 1

Function Redefinition Errors

Posted: Sat Jun 16, 2012 5:12 pm
by RandomDever
So I'm building a new version of my engine from scratch for my next big project and I've been running into a problem lately.
Example:

Code: Select all

1>input.obj : error LNK2005: "bool Debug::debug" (?debug@Debug@@3_NA) already defined in program.obj
1>input.obj : error LNK2005: "class std::basic_ofstream<char,struct std::char_traits<char> > Debug::debugFile" (?debugFile@Debug@@3V?$basic_ofstream@DU?$char_traits@D@std@@@std@@A) already defined in program.obj
1>debug.obj : error LNK2005: "bool Debug::debug" (?debug@Debug@@3_NA) already defined in program.obj
1>debug.obj : error LNK2005: "class std::basic_ofstream<char,struct std::char_traits<char> > Debug::debugFile" (?debugFile@Debug@@3V?$basic_ofstream@DU?$char_traits@D@std@@@std@@A) already defined in program.obj
Is there any way to prevent this from happening?
It's probably some ridiculously obvious well known programming practice, but keep in mind I don't have a college education.
Any help is greatly appreciated. :)
Thank you.

Re: Function Redefinition Errors

Posted: Sat Jun 16, 2012 7:53 pm
by bbguimaraes
My first guess is include guards are missing.

Re: Function Redefinition Errors

Posted: Sat Jun 16, 2012 9:09 pm
by RandomDever
If you mean the #ifndef guards then no I remembered those ( which only serves to confuse me more ).

EDIT: If I knew how to make global variables that I can access from any file this problem could be resolved. Does anyone know how to do that?
Because right now I'm just using namespaces, which apparently don't work as I intend.

Re: Function Redefinition Errors

Posted: Sat Jun 16, 2012 10:55 pm
by bbguimaraes

Code: Select all

// some_file.h
#ifndef SOME_FILE_H
#define SOME_FILE_H

namespace Debug {
    bool debug;
}

#endif // SOME_FILE_H

// other_file.cpp
#include <some_file.h>

void f() {
    Debug::debug = true;
}
Does that help?

Re: Function Redefinition Errors

Posted: Sun Jun 17, 2012 12:22 am
by RandomDever
Apparently, not. I tried it and I still got the linker errors. :(

Re: Function Redefinition Errors

Posted: Sun Jun 17, 2012 1:11 am
by RandomDever
I don't think I will ever understand how c++ works.
It works now... I have no idea why. It just does.
Well thanks for trying anyways...

Re: Function Redefinition Errors

Posted: Sun Jun 17, 2012 12:15 pm
by bbguimaraes
"Already defined" errors occur when you declare a name (which can be a variable, class, function, etc) on more than one place. You need to declare the name once in a header file with include guards. Then, on other files where you use the name, you need only include the file, not declare it again.

Try reducing your code to the least necessary to reproduce the error. If you still can't solve it, post a sample and we will try to help.

And don't worry, c++ takes time to understand (and a lifetime to master).

Re: Function Redefinition Errors

Posted: Mon Jun 18, 2012 9:21 am
by YourNerdyJoe
change

Code: Select all

namespace Debug {
    bool debug;
}
to

Code: Select all

namespace Debug {
    static bool debug;
}
and it should work

Re: Function Redefinition Errors

Posted: Mon Jun 18, 2012 10:03 am
by Falco Girgis
RandomDever wrote:It's probably some ridiculously obvious well known programming practice, but keep in mind I don't have a college education.
I take personal offense to this. Even though I HAVE a college education, I learned to code and develop on my own time. That's taking credit away from me teaching myself and giving credit to my college which didn't teach me shit. A degree means nothing about your programming efficacy. I know plenty of college grads who can't code for shit and highschool dropouts who are coding gurus. Don't let me catch you saying shit like that again. ;)

Considering the fact that you haven't bothered to post the offending header file, I take it we're all stabbing in the dark here? My turn.
bbguimaraes wrote:

Code: Select all

namespace Debug {
    bool debug;
}

#endif // SOME_FILE_H

// other_file.cpp
#include <some_file.h>

void f() {
    Debug::debug = true;
}
That is most DEFINITELY not going to work. That's probably what is causing the error anyway.

Every .cpp file including that header file now has a duplicate declaration of the debug boolean flag, hence the linker errors.
YourNerdyJoe wrote:change

Code: Select all

namespace Debug {
    bool debug;
}
to

Code: Select all

namespace Debug {
    static bool debug;
}
and it should work
If your definition of "work" is compile, link, and run, then yes, it will work.

If your definition of "work" is operate correctly, then no. What you have now done is given each .cpp its very own private (static) instance of the debug flag. This resolves the duplicate symbol, because every .cpp file now has its own debug flag, but if the intent of the global was to allow access to this flag throughout the program, you're still wrong.

One word: EXTERN

Change

Code: Select all

namespace Debug {
    bool debug;
}
to

Code: Select all

namespace Debug {
    extern bool debug;
}
within your header file.

Then put

Code: Select all

namespace Debug {
    bool debug;
}
into a .cpp file somewhere.

The first extern declaration tells each .cpp file including the header file that there exists a variable declared elsewhere called debug. You are NOT allocating that variable, you are simply telling the compiler that it is allocated elsewhere.

Then the second declaration in the .cpp file actually allocates the variable. When the linker links each file's extern declaration from the header file, they now all point back to the same variable allocated within the .cpp.

Re: Function Redefinition Errors

Posted: Mon Jun 18, 2012 11:51 am
by bbguimaraes
Yeah, that was my bad, I forgot about the extern. Your Debug::debugFile is going to need to be declared as external and be defined on a cpp file too. The definitions on the .cpp file can be made shorter:

Code: Select all

bool Debug::debug;
ofstream Debug::debugFile;
RandomDever wrote:EDIT: If I knew how to make global variables that I can access from any file this problem could be resolved. Does anyone know how to do that?
Because right now I'm just using namespaces, which apparently don't work as I intend.
Namespaces exist to avoid name collisions. Its purpose has nothing to do with what we are discussing here. To declare a global variable and use it in other files, you need to do it as Falco showed. But try to avoid using global variables, if you can. Or better said, try to avoid making code dependent on global variables (which usually leads to not using them at all).

Re: Function Redefinition Errors

Posted: Mon Jun 18, 2012 8:29 pm
by YourNerdyJoe
Falco Girgis wrote:
YourNerdyJoe wrote:change

Code: Select all

namespace Debug {
    bool debug;
}
to

Code: Select all

namespace Debug {
    static bool debug;
}
and it should work
If your definition of "work" is compile, link, and run, then yes, it will work.

If your definition of "work" is operate correctly, then no. What you have now done is given each .cpp its very own private (static) instance of the debug flag. This resolves the duplicate symbol, because every .cpp file now has its own debug flag, but if the intent of the global was to allow access to this flag throughout the program, you're still wrong.

One word: EXTERN

Change

Code: Select all

namespace Debug {
    bool debug;
}
to

Code: Select all

namespace Debug {
    extern bool debug;
}
within your header file.

Then put

Code: Select all

namespace Debug {
    bool debug;
}
into a .cpp file somewhere.

The first extern declaration tells each .cpp file including the header file that there exists a variable declared elsewhere called debug. You are NOT allocating that variable, you are simply telling the compiler that it is allocated elsewhere.

Then the second declaration in the .cpp file actually allocates the variable. When the linker links each file's extern declaration from the header file, they now all point back to the same variable allocated within the .cpp.
Didn't realize that was the difference between static and extern. Thanks for the edjukation Falco ;)