1. Not finding help here? Sign up for a free 30min tutor trial with Chegg Tutors
    Dismiss Notice
Dismiss Notice
Join Physics Forums Today!
The friendliest, high quality science and math community on the planet! Everyone who loves science is here!

(C++) ubuntu g++ bug: multiple definition of a function. What went wrong?

  1. Jan 28, 2012 #1
    1. The problem statement, all variables and given/known data

    I can't understand what's causing this bug.
    I'm not trying to actually use this program, but it's just something I made up to learn how it works, and understand why things don't work, while I'm learning C++. So my question is, what's causing this program to get this error?

    2. Relevant equations

    add.cpp
    Code (Text):

    int add(int x, int y)
    {
        return x + y;
    }
     
    main.cpp
    Code (Text):

    #include <iostream>
    #include "math.h"
    using namespace std;

    int main()
    {
        cout << "The sum of 3 and 4 is " << add(3, 4) << endl;
        subtract(1, 2);
        hello(4, 5);
        return 0;
    }
     
    subtract.cpp
    Code (Text):

    #include "math.h"

    int subtract(int x, int y)
    {
        return add(4, 5)
    }
     
    math.h
    Code (Text):

    #ifndef MATH_H
    #define MATH_H
    int add(int x, int y);
    int subtract(int x, int y);

    int hello(int x, int y)
    {
        return 4;
    }
    #endif
     

    These 4 files (add.cpp, main.cpp, subtract.cpp, math.h) are all in the same directory. I'm running g++ on ubuntu, so in that directory I type in:

    Code (Text):

    g++ -g *.cpp
     
    and the output is:

    Code (Text):

    /home/myname/Desktop/CS/math.h:8: multiple definition of 'hello(int,int)'
    /tmp/ccWAqLWY.o:/home/myname/Desktop/CS/math.h:8: first defined here
    collect2: ld returned 1 exit status
     



    3. The attempt at a solution
    I think it has to do with the header file includes. I thought that it isn't being defined twice, because the second time math.h is included, it would see the #ifndef and not redefine it again. (???)
    Can anyone explain what went wrong? Much thanks.
     
  2. jcsd
  3. Jan 28, 2012 #2

    D H

    User Avatar
    Staff Emeritus
    Science Advisor

    Your program violates the one definition rule (see http://en.wikipedia.org/wiki/One_Definition_Rule). You have the function hello(int, int) defined multiple times, once in subtract.cpp, and again in main.cpp.

    You can define functions in headers, but they need to be qualified with inline. For example,
    Code (Text):
    inline int hello(int x, int y)
    {
        return 4;
    }
     
  4. Jan 28, 2012 #3

    jtbell

    User Avatar

    Staff: Mentor

    You're probably thinking that the '#ifndef MATH_H' trick is supposed to prevent this sort of thing, but it works only within the compilation of a single file.

    Your command 'g++ -g *.cpp' doesn't act as if it were concatenating add.cpp, main.cpp and subtract.cpp together and then compiling them all in one go, as if they were in a single file; instead, it compiles the three files separately from each other. If you were to compile to unlinked .o files, both main.o and subtract.o would contain definitions of the function subtract(). This is what the linker is complaining about (note the error message comes from the linker, 'ld', not from the compiler itself).

    [added] Suppose the compiler compiles main.cpp first. When it finishes main.cpp, it loses all its "internal memory" of what happened in that file, including the fact that the symbol MATH_H has been defined. When it then compiles subtract.cpp, the symbol MATH_H is now undefined, and so the compiler compiles the definition of subtract() again.

    Try concatenating the two files main.cpp and subtract.cpp into a single file that has two copies of the line '#include "math.h"' and see the difference.
     
    Last edited: Jan 28, 2012
  5. Jan 28, 2012 #4
    Thanks so much for telling me about the One Definition Rule. I hadn't heard of it before, and I tried reading that article but it was hard to understand. From what I can understand from that article, it looks like I was doing things right by putting
    "ifndef NAME
    def NAME
    Code (Text):

    endif"

    How is it defined multiple times, when I have the include guard?

    I tried to see the result of the preprocessor to see if it actually did insert the header file twice by typing in this command to the terminal:

    [CODE]
    g++ -E *.cpp -o output
     
    And when I opened the resulting output file in a text editor, it looked like this:

    Code (Text):

    # 1 "subtract.cpp"
    # 1 "<built-in>"
    # 1 "<command-line>"
    # 1 "subtract.cpp"
    # 1 "math.h" 1



    int add(int x, int y);
    int subtract(int x, int y);

    int hello(int x, int y)
    {
     return 4;
    }
    # 2 "subtract.cpp" 2

    int subtract(int x, int y)
    {
     return add(4,5);
    }
     
    But, I had expected it to simply copy and paste the header files where the "#include"s were. Could you tell me what this means? I'm curious because it seems to contradict the idea that wherever I include a header file, that header file gets copied and pasted directly into that spot. Thanks!
     
  6. Jan 28, 2012 #5

    jtbell

    User Avatar

    Staff: Mentor

    See my post above.
     
  7. Jan 28, 2012 #6
    Thanks for your post. Could you elaborate what you mean here, maybe with an example? I don't think I quite understand. Thanks!

    edit:
    So, here's what I'm thinking so far. Maybe the preprocessor makes main.cpp look like this:

    Code (Text):

    #include <iostream>  //Except this would be expanded a whole lot

    int add(int x, int y); // function prototype for add.h
    int subtract(int x, int y);

    int hello(int x, int y)
    {
        return 4;
    }


    using namespace std;


    int main()
    {
        cout << "The sum of 3 and 4 is " << add(3, 4) << endl;
        subtract(1,2);
        hello(4,5);
        return 0;
       
    }

     

    And subtract.cpp might look like this after being preprocessed:
    Code (Text):

    int add(int x, int y); // function prototype for add.h
    int subtract(int x, int y);

    int hello(int x, int y)
    {
        return 4;
    }


    int subtract(int x, int y)
    {
        return add(4,5);
    }
     
    So when it tries to link it together, the linker doesn't know whether to use the address of the function "hello" that is in main.cpp, or the address of the function "hello" that is in subtract.cpp, because they have the same name? Why doesn't it use the particular "hello" function that is in the current file, and if it isn't go look for it in another file?
    ...
    *lightbulb* Maybe it's because if there was, say, a multiply.cpp that also included "math.h", then there would be two "hello" functions to choose from? And then, since the preprocessor doesn't keep track of which functions are both from the same header file (and therefore identical), the linker has to have an error, in order to prevent programmers from having undefined results by randomly choosing one function when there could be two different functions with the same name?

    Am I on the right track? It's making my mind spin...

    This seems like an issue of scope of the functions. Maybe since my functions aren't defined in a class, they have a global scope. Can they possibly conflict with the standard library functions as well? Do I have to keep a large list of all the function names that are "already taken" by the standard libraries, in order to avoid naming conflicts such as my "multiple definition of hello" error?
     
    Last edited: Jan 28, 2012
  8. Jan 28, 2012 #7

    jtbell

    User Avatar

    Staff: Mentor

    Basically yes.

    The linker doesn't know anything about .cpp files. What the linker sees is a collection of chunks of compiled object code that have names. Within those chunks of object code are references (function calls) to other named chunks of object code. It's the job of the linker to convert ("resolve") the names in those function calls to actual addresses to jump to during program execution. If there are two chunks named "hello", the linker has a problem: which one does it use when it encounters a call to "hello"?

    In C++, the concept of "namespaces" addresses this problem. In effect, all standard library function names are prefixed with "std::". The "using namespace std;" statement that you've probably been slapping into every program that you've written so far, without knowing why, basically tells the compiler, "whenever you see a call to a function that doesn't look like 'something::functionname()', first assume I mean 'std::functionname()' and try to find a match for it; if there's no match, then look for plain old 'functionname()' among the functions that I've defined."

    You can define your own namespace, so that you can have both 'std::sin()' and, say, 'nishiura::sin()' without running into multiple-definition problems.

    (I've probably oversimplified here, so use this only as a starting point for further study of namespaces!)
     
  9. Jan 30, 2012 #8
    This is not correct. While unnamed namespaces are the preferred way to provide internal linkage with C++, namespaces in general will not solve multiple definition problems*.

    The two acceptable solutions to the OP's problem are:

    • Put the hello function in an unnamed namespace.
    • Define the hello function in a seperate translation unit (cpp file), and just have a prototype (declaration) in the header file.


    * for example this would not successfully build:

    h1.h
    Code (Text):
    #ifndef H1_H
    #define H1_H

    namespace my_namespace
    {
        void function1(){}
    }

    #endif
    h2.h
    Code (Text):
    #ifndef H2_H
    #define H2_H

    void function2();

    #endif
    translation_unit2.cpp
    Code (Text):
    #include "h1.h"
    #include "h2.h"

    void function2() {

        my_namespace::function1();
    }
    main.cpp
    Code (Text):
    #include "h1.h"
    #include "h2.h"


    int main()
    {
        my_namespace::function1();
    }
    To make it build, one could use an anonymous namespace in h1.h (and forgo the "my_namespace::" prefixes in both cpp files).

    h1.h
    Code (Text):
    #ifndef H1_H
    #define H1_H

    namespace
    {
        void function1(){}
    }

    #endif
     
    Last edited: Jan 30, 2012
  10. Jan 30, 2012 #9

    D H

    User Avatar
    Staff Emeritus
    Science Advisor

    I disagree completely. Namespaces were invented precisely to solve the multiple definition problem. Package X from vendor A has a class named Foo and a function bar, so does package Y from vendor B. There are no name collisions between the two packages if the vendors enclosed there packages in different namespaces.

    You missed a third acceptable solution, which is to prefix the function spec in the header with the inline keyword.

    Big alarm bells go off in my head when I'm called upon to review some chunk of code and see the use of unnamed namespace.
     
  11. Jan 30, 2012 #10
    No, that's a different problem. The problem we're discussing in this thread is the same code being compiled into two different translation units, and then there is an error upon linking.


    Yes, I thought of that, but I wasn't sure that this necessarily implied internal linkage. But you are correct, inline should work as well, although AFAIK it only works for functions. Unnamed namespaces works for global variables and classes as well.


    Well, it's the method one is supposed to use when internal linkage is required.
     
Know someone interested in this topic? Share this thread via Reddit, Google+, Twitter, or Facebook