Thread: Mutual header inclusion breaks variable definition

  1. #1
    Registered User
    Join Date
    Aug 2011
    Location
    Montreal, Quebec, Canada
    Posts
    73

    Mutual header inclusion breaks variable definition

    Hello there. I have not dabbled much in C++ in a long while but I am feeling like making a small project for fun. In this project I encountered this annoying problem on a secondary function of the application (i.e. not what it's core use is). Maybe I am just too tired and I am not seeing the horrible design or maybe I am missing something obvious :/

    I have tried a few changes like moving declarations and definitions around, but it does not seem to go away.

    Basically, bar.h uses a class defined in foo.h to instantiate from it and to create a macro using that instance. In turn, that macro will be used in both foo.cpp and main.cpp. I am getting the following error:
    build/Debug/GNU-Linux-x86/bar.o:(.bss+0x0): multiple definition of `SOMEVAR'
    build/Debug/GNU-Linux-x86/main.o:/home/alexandre/NetBeansProjects/tests/main.cpp:10: first defined here
    collect2: ld returned 1 exit statuse
    I have tried the simplest code possible (stripping *everything* that is not related to this issue) and get the exact same error so I know this is what is causing me trouble.

    Here are the related files:
    Code:
    /* 
     * File:   foo.h
     * Author: alexandre
     *
     * Created on August 21, 2011, 12:49 AM
     */
    
    #ifndef FOO_H
    #define	FOO_H
    
    class Foo {
    public:
        void do_something(int t);
    };
    
    #endif	/* FOO_H */
    Code:
    /* 
     * File:   bar.h
     * Author: alexandre
     *
     * Created on August 21, 2011, 12:49 AM
     */
    
    #ifndef BAR_H
    #define	BAR_H
    
    #define WHATEVER
    
    #ifdef WHATEVER
        #include "foo.h"
    
        Foo SOMEVAR;
        #define SOMEMACRO(a) SOMEVAR.do_something(a)
    #else // WHATEVER
        #define SOMEMACRO(a) //does nothing
    #endif
    
    #endif	/* BAR_H */
    Code:
    /*
     * File:   foo.cpp
     * Author: alexandre
     *
     * Created on August 21, 2011, 12:49 AM
     */
    
    #include "foo.h"
    
    void Foo::do_something() {
        // whatever
    }
    Code:
    /*
     * File:   bar.cpp
     * Author: alexandre
     *
     * Created on August 21, 2011, 12:49 AM
     */
    
    #include "bar.h"
    Code:
    /* 
     * File:   main.cpp
     * Author: alexandre
     *
     * Created on August 21, 2011, 12:48 AM
     */
    
    #include "bar.h"
    
    int main(int argc, char** argv) {
        SOMEMACRO("whatever");
        return 0;
    }
    This exact code generates the error. I am using the latest version of g++ on Netbeans IDE.

    Finally, I have tried to add "guards" to try not to instantiate twice the same class. Apparently that does not do anything else different as I get the exact same problem.
    Code:
    #ifdef WHATEVER
        #ifndef WHATEVER_INIT
        #define WHATEVER_INIT
            #include "foo.h"
    
            Foo SOMEVAR;
            #define SOMEMACRO(a) SOMEVAR.do_something(a)
        #endif //WHATEVER_INIT
    #else // WHATEVER
        #define SOMEMACRO(a) //does nothing
    #endif
    Sorry for the code dumping but I think the structure here matters a lot to the problem.

    Thank you very much.

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    The problem is that you defined a variable in a header. So, if the header is included in multiple translation units (source file + headers), the variable will be defined in each translation unit that it is included, breaking the one definition rule. Header inclusion guards cannot prevent this as they only guard against multiple inclusion within a single translation unit.

    Why do you need the macro in the first place?
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Aug 2011
    Location
    Montreal, Quebec, Canada
    Posts
    73
    Thank you for the quick reply. To be honest I am trying to make a simple error logger (Bar in this case) aso that I know when something goes wrong and what goes wrong in my application. I wanted to make it so that if I call the macro it would just do nothing if DEBUG_MODE is not defined. However it seems that it would be difficult to do and maybe I should think of simply encapsulating my IO class (Foo, in this case).

  4. #4
    Registered User
    Join Date
    Aug 2011
    Location
    Montreal, Quebec, Canada
    Posts
    73
    Finally I decided to create a third class which will be taking in charge matters related to error logging (which may get a little more complex should I work seriously on this project). I had the same problem but remembered the "extern" keyword which solved my problem of multiple definitions.

    Code:
    //
    // system.h
    //
    
    #ifndef SYSTEM_H
    #define	SYSTEM_H
    
    #define DEBUG_MODE
    
    #ifdef DEBUG_MODE
        #include "iomanagement.h"
    
        class C_DBG_LOGGER {
        private:
            IOManagement io;
        public:
            C_DBG_LOGGER();
    
            void Write(const char*);
        };
    
        extern C_DBG_LOGGER DBG_LOGGER;
    
        #define DIE(a) DBG_LOGGER.Write(a)
    #else
        #define DIE(a) // left empty
    #endif // DEBUG_MODE
    
    #endif	// SYSTEM_H
    This is very basic and has no features at all but does the job for the moment.
    Last edited by Alexandre; 08-21-2011 at 05:42 PM.

  5. #5
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Ah, I was hesitant to suggest extern because global variables should be avoided, but in this case your use of it is legitimate.

    Incidentally, instead of DEBUG_MODE, you might consider if checking for the standard macro NDEBUG would be more appropriate.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Odd error on header file inclusion
    By anatoly in forum C Programming
    Replies: 5
    Last Post: 05-30-2010, 12:20 PM
  2. Header file multiple inclusion question
    By Loctan in forum C++ Programming
    Replies: 16
    Last Post: 05-04-2008, 08:25 PM
  3. Header inclusion causing errors
    By cjschw in forum C++ Programming
    Replies: 12
    Last Post: 08-11-2004, 03:48 PM
  4. class and header inclusion problem.
    By Eibro in forum C++ Programming
    Replies: 2
    Last Post: 12-02-2002, 10:12 PM
  5. Inclusion of header class
    By Unregistered in forum C++ Programming
    Replies: 0
    Last Post: 12-08-2001, 03:33 PM