Dismiss Notice
Join Physics Forums Today!
The friendliest, high quality science and math community on the planet! Everyone who loves science is here!

Xcode, Duplicate symbol error during compilation? (C)

  1. Aug 1, 2010 #1
    I'm following a tutorial off of the internet - http://masters-of-the-void.com/book10.htm" [Broken] one to be exact - and whenever I try and compile I get this error:

    [PLAIN]http://dl.dropbox.com/u/1426380/Screen%20shot%202010-08-01%20at%2015.26.11.png [Broken]

    I've tried going over my code again and again, but seeing as it doesn't seem to tell me where the error is happening, it's really difficult for me (as a beginner with C) to actually find the problem.

    I'll post all my code below to help you out.

    main.c:
    Code (Text):
    #include "main.h"
    #include "myFunctions.c"

    int numDatabaseEntries = 0;
    struct DatabaseEntry * gDatabase = NULL;

    int     main()          //Main program function
    {
       
        bool keepRunning = true;    //Declares and assigns variable to allow program to loop
        char userInput[11];         //String for user input
       
        printf("Welcome to the CD Database!\n");    //Welcome message. Only displayed once as it is outside of the 'while' block
       
        while ( keepRunning == true )   //Keeps program looping while the keepRunning variable is true
        {
            printf( "\nType NEW, LIST, CLEAN or QUIT:\n>" );
            scanf( "%5s", userInput );
            fpurge( stdin );
           
            if ( strcmp( userInput, "NEW" ) == 0 )
                NewEntry();         //Code for new database entry
            else if ( strcmp( userInput, "LIST" ) == 0 )
                List();             //Code for list database
            else if ( strcmp( userInput, "CLEAN" ) == 0 )
                CleanUp();          //Code for cleanup
            else if( strcmp( userInput, "QUIT" ) == 0 )
            {
                keepRunning = false;                        //Ends program by exiting out of the loop
                CleanUp();                                  //Frees memory before quitting
            }
            else
                printf( "Error, command '%s' is unknown.", userInput ); //Prints unknown command to warn user
           
        }
       
        printf("\nThank you for using the CD Database.");
       
        return 0;                   //Returns ok value to OS
    }
     
    myFunctions.c:
    Code (Text):
    #include "main.h"

    struct DatabaseEntry    //Defines custom data structure to use to store information on each CD
    {
        char    artist[40];
        char    composer[40];
        char    albumName[40];
        int     trackCount;
        bool    isSampler;
       
    };

    void    NewEntry()      //Function used for entering a new entry to database
    {
        char yesOrNo;       //For 'is sampler' later on
       
        //Create new array element, or new array if no array exists
        if ( gDatabase == NULL )
        {
            gDatabase = malloc( sizeof(struct DatabaseEntry) );
            if ( gDatabase == NULL )        //Still null? Error must have occured
            {
                printf( "Error, couldn't create a new entry.\n" );
                return;
            }
        }
        else
        {
            struct DatabaseEntry * newPtr = NULL;   //Declare temporary Database holder to use realloc with
            newPtr = realloc( gDatabase, ( numDatabaseEntries + 1 ) * sizeof( struct DatabaseEntry ) ); //Make newPtr one unit bigger than old database, shove everything in it
            if ( newPtr == NULL )   //Out of memory?
            {
                printf( "Error, couldn't create a new entry.\n" );
                return;             //Keeps gDatabase as old pointer
            }
           
            gDatabase = newPtr;     //Copy all of newPtr back into gDatabase, make gDatabase main database again.
        }
       
        numDatabaseEntries += 1;        //Increase database entries by 1;
       
        //Allow user to input data and store it in the database
        printf( "\nArtist name: " );
        scanf( "%39s", gDatabase[ numDatabaseEntries - 1 ].artist );
        fpurge( stdin );
       
        printf( "Composer: " );
        scanf( "%39s", gDatabase[ numDatabaseEntries - 1 ].composer );
        fpurge( stdin );
       
        printf( "Album name: " );
        scanf( "%39s", gDatabase[ numDatabaseEntries - 1 ].albumName );
        fpurge( stdin );
       
        printf ("Track count: " );
        scanf( "%d", &gDatabase[ numDatabaseEntries -1 ].trackCount );
        fpurge( stdin );
       
        printf( "Sampler? (y/n): " );
        scanf( "%c", &yesOrNo );
        fpurge( stdin );
       
        gDatabase[ numDatabaseEntries - 1 ].isSampler = false;                                      //Assigns it as false initially
        gDatabase[ numDatabaseEntries - 1 ].isSampler = ( yesOrNo == 'y' || yesOrNo == 'Y' );       //Assigns it as true if Y or y is inputed
       
    }

    void    List()          //Function to list CDs
    {
        if ( gDatabase == NULL )
        {
            printf( "There are no CDs in the database!" );
            return;
        }
       
        for ( int x = 0; x < numDatabaseEntries; ++x )
        {
            printf( "\nArtist name: %s\n", gDatabase[ x ].artist );
            printf( "Composer: %s\n", gDatabase[ x ].composer );
            printf( "Album name: %s\n", gDatabase[ x ].albumName );
            printf( "No. of tracks: %d\n", gDatabase[ x ].trackCount );
            if ( gDatabase[ x ].isSampler )
                printf( "This CD is a sampler\n" );
        }
       
    }

    void    CleanUp()       //Function to free memory
    {
        if ( gDatabase != NULL )
        {
            free( gDatabase );
            gDatabase = NULL;
            numDatabaseEntries = 0;
        }
       
    }
    main.h:
    Code (Text):
    #include <stdio.h>
    #include <stdbool.h>
    #include <string.h>
    #include <stdlib.h>

    struct DatabaseEntry;

    //Defines custom data structure to use to store information on each CD

    int numDatabaseEntries;
    struct DatabaseEntry * gDatabase;

    void NewEntry();
    void List();
    void CleanUp();
    I think it's something to do with the data structure not being declared properly, I've tried doing different things with it but none of them have got rid of the error.

    I apologise if I've done something completely wrong here, the lesson that I was following was a bit vague at times, and i wasn't that sure on where to put things in terms of header files etc.

    Thanks.
     
    Last edited by a moderator: May 4, 2017
  2. jcsd
  3. Aug 2, 2010 #2
    Lovely helpful IDE you have there....

    Did you try clicking on the ...more... in that error line to see if it can provide more? Like which file and line number is causing it to choke?

    At first glance your code looks fine. If you can't get any more help from your IDE I would start changing names and moving code around to see if I could have any effect on the problem.
     
  4. Aug 2, 2010 #3

    Mark44

    Staff: Mentor

    The first error shown is a linker error, showing a duplicate symbol for _NewEntry. It's likely that gcc already has a variable or function or something with this name. I would change the name of the NewEntry function to eliminate this linker error. Something like New_Entry would probably work, or NewSongEntry, or ???
     
  5. Aug 2, 2010 #4
    Just tried changing the name of NewEntry numerous times, but it had no effect. The exact same error came up.

    Also, I tried making a new project and copying all the code over, just to see if XCode had done something messy when I was experimenting with headers. But the same error still came up.

    For schip666!, here's the complete error message. It is rather vague to be honest:

    [PLAIN]http://dl.dropbox.com/u/1426380/Screen%20shot%202010-08-02%20at%2021.09.21.png [Broken]

    I'm really confused as to why this is happening, there must be a reason for it, surely?
     
    Last edited by a moderator: May 4, 2017
  6. Aug 2, 2010 #5
    If you declare a boolean variable as TRUE is it then a static variable? If so you can't change it in the program to FALSE.
    Try using 'BOOL keeprunning;' without assigning a value.
     
  7. Aug 3, 2010 #6

    Mark44

    Staff: Mentor

    In main.c, you have a preprocessor directive where you're including myFunctions.c. Take that line out. You should never #include a C source file - only .h header files.

    I think this is where your problem lies - the compiler is being fooled into thinking there are two definitions for GetEntry(). I'm guessing that it also thinks there are two definitions for List() and Cleanup() as well, but the linker is probably choking on the first of these, and giving up.
     
  8. Aug 3, 2010 #7
    Yep, you got it. I thought that you had to include the .c file to let the compiler know about the contents (in the case, the functions it contains), so this isn't the case? All you have to do is have it in the source folder?
     
  9. Aug 3, 2010 #8

    D H

    User Avatar
    Staff Emeritus
    Science Advisor

    In the old days you had to specify things explicitly in a makefile. Now your IDE knows what to build. Never, ever, ever #include a .c file. It is legal to do so only because the C preprocessor is incredibly stupid. It also almost always very bad form.
     
  10. Aug 3, 2010 #9
    Ok, I'll keep that in mind.

    Briefly, could you sum up what I should use .h files for and what I should use .c files for? I'm a bit confused at the moment.
     
  11. Aug 3, 2010 #10

    Mark44

    Staff: Mentor

    Use .h files for function prototypes, struct template definitions, and global constants. Use .c files for function definitions (i.e., where you actually define how the functions work as opposed to their signatures). That should roughly cover the division of what goes where.
     
  12. Aug 3, 2010 #11

    jtbell

    User Avatar

    Staff: Mentor

    The problem with using an integrated IDE like Xcode for introductory level programming is that it obscures the stages of the compilation/linking process, which are the key to why .c and .h files exist.

    To summarize what you might have read or heard already, when you compile a program you actually do two things:

    (1) You compile the source code into machine code. Each function produces a chunk of machine code.

    (2) You link the chunks of compiled machine code from your source code, with other chunks of machine code from system libraries, to produce the complete executable program.

    Basically, a .c file contains code for functions that are compiled separately from the rest of the program. A .h file "tells" other .c files how the functions in the separately-compiled .c file are supposed to be called.

    Here's an example, starting with a simple complete program with a few functions, in a single file. It's C++ because that's what I'm familiar with, but the basic program structure is the same as in C. Instead of .c files I use .cpp files.

    Code (Text):

    // lorentz.cpp - main function and sub-functions together as a
    // complete program

    #include <iostream>
    #include <cmath>

    using namespace std;

    double lorentz_gamma (double v)
    {
        const double c = 3e8;
        return 1.0 / sqrt (1 - (v*v)/(c*c));
    }

    double lorentz_xprime (double x, double t, double v)
    {
        return lorentz_gamma(v) * (x - v*t);
    }

    double lorentz_tprime (double x, double t, double v)
    {
        const double c = 3e8;
        return lorentz_gamma(v) * (t - v*x/(c*c));
    }

    int main ()
    {
        cout << "Lorentz transformation calculator" << endl;
        cout << "Enter x, t and v: ";
        double x, t, v;
        cin >> x >> t >> v;
        cout << "The transformed x and t are "
             << lorentz_xprime(x, t, v) << " "
             << lorentz_tprime(x, t, v) << endl;
        return 0;
    }
     
    Here's how I compile, link and run it at the Unix command line, in a Terminal window under Mac OS:

    Code (Text):

    $ g++ lorentz.cpp -o lorentz
    $ ./lorentz
    Lorentz transformation calculator
    Enter x, t and v: 0 1 2e8
    The transformed x and t are -2.68328e+08 1.34164
    Jons-Mac-Pro:lorentz jtbell$
     
    Now I decide that I want to split the functions into a separate file so I can use them in other programs. Further, I want to compile them only once, and then link the compiled code into other programs as necessary. (If these were large functions, this could save a significant amount of compilation time.)

    So I move the functions into a separate file:

    Code (Text):

    // lorentz_subs.cpp - functions for calculating
    // the Lorentz transformation

    double lorentz_gamma (double v)
    {
        const double c = 3e8;
        return 1.0 / sqrt (1 - (v*v)/(c*c));
    }

    double lorentz_xprime (double x, double t, double v)
    {
        return lorentz_gamma(v) * (x - v*t);
    }

    double lorentz_tprime (double x, double t, double v)
    {
        const double c = 3e8;
        return lorentz_gamma(v) * (t - v*x/(c*c));
    }
     
    I try compiling it separately, without linking it to anything else. The "-c" switch in the "g++" command means "compile only".

    Code (Text):

    $ g++ lorentz_subs.cpp -c
    lorentz_subs.cpp: In function 'double lorentz_gamma(double)':
    lorentz_subs.cpp:4: error: 'sqrt' was not declared in this scope
    $
     
    Oops, I need to declare sqrt(), so I add an include statement for the header file that contains the declarations of the math functions. ("math.h" in C corresponds to "cmath" in C++.)

    Code (Text):

    // lorentz_subs.cpp - functions for calculating
    // the Lorentz transformation

    #include <cmath>

    double lorentz_gamma (double v)
    {
        const double c = 3e8;
        return 1.0 / sqrt (1 - (v*v)/(c*c));
    }

    double lorentz_xprime (double x, double t, double v)
    {
        return lorentz_gamma(v) * (x - v*t);
    }

    double lorentz_tprime (double x, double t, double v)
    {
        const double c = 3e8;
        return lorentz_gamma(v) * (t - v*x/(c*c));
    }
     
    Now it compiles successfully:

    Code (Text):

    $ g++ lorentz_subs.cpp -c
    $
     
    I now have a file named lorentz_subs.o which contains the compiled code for these functions.

    Now I turn to the main program. I delete the functions and rename the file :

    Code (Text):

    // lorentz_main.cpp - main program only

    #include <iostream>

    using namespace std;

    int main ()
    {
        cout << "Lorentz transformation calculator" << endl;
        cout << "Enter x, t and v: ";
        double x, t, v;
        cin >> x >> t >> v;
        cout << "The transformed x and t are "
             << lorentz_xprime(x, t, v) << " " << lorentz_tprime(x, t, v) << endl;
        return 0;
    }
     
    I removed the #include <cmath> because this file no longer uses any of the math functions directly. I try to compile it, again without linking:

    Code (Text):

    $ g++ lorentz_main.cpp -c
    lorentz_main.cpp: In function 'int main()':
    lorentz_main.cpp:12: error: 'lorentz_xprime' was not declared in this scope
    lorentz_main.cpp:12: error: 'lorentz_tprime' was not declared in this scope
    $
     
    I need to declare the two functions that I removed. One way is to insert prototypes that indicate the return type, and the types of the arguments. This allows the compiler to check that I'm calling the functions properly.

    Code (Text):

    // lorentz_main.cpp - main program only

    #include <iostream>

    using namespace std;

    double lorentz_xprime (double x, double t, double v);
    double lorentz_tprime (double x, double t, double v);

    int main ()
    {
        cout << "Lorentz transformation calculator" << endl;
        cout << "Enter x, t and v: ";
        double x, t, v;
        cin >> x >> t >> v;
        cout << "The transformed x and t are "
             << lorentz_xprime(x, t, v) << " " << lorentz_tprime(x, t, v) << endl;
        return 0;
    }
     
    Compile it:

    Code (Text):

    $ g++ lorentz_main.cpp -c
    $
     
    It works! Now I have a file named lorentz_main.o, and I can link the two separately-compiled parts of the program and run it:

    Code (Text):

    $ g++ lorentz_main.o lorentz_subs.o -o lorentz
    $ ./lorentz
    Lorentz transformation calculator
    Enter x, t and v: 0 1 2e8
    The transformed x and t are -2.68328e+08 1.34164
    $
     
    But it's a nuisance, having to write out the prototypes for those functions every time I write a program that uses them. So I put them into a separate file, lorentz_subs.h, and "include" that file when necessary. The preprocessor in effect "pastes" those prototypes into whatever file contains the "include" directive. So now I have this:

    Code (Text):

    // lorentz_subs.h - prototypes for Lorentz transformation functions

    double lorentz_gamma (double v);
    double lorentz_xprime (double x, double t, double v);
    double lorentz_tprime (double x, double t, double v);
     
    (I added a prototype for lorentz_gamma() in case I might want to use it in some other program.)

    Code (Text):

    // lorentz_main.cpp - main program only

    #include <iostream>
    #include "lorentz_subs.h"

    using namespace std;

    int main ()
    {
        cout << "Lorentz transformation calculator" << endl;
        cout << "Enter x, t and v: ";
        double x, t, v;
        cin >> x >> t >> v;
        cout << "The transformed x and t are "
             << lorentz_xprime(x, t, v) << " " << lorentz_tprime(x, t, v) << endl;
        return 0;
    }
     
    I can compile these files together with lorentz_subs.cpp either one step at a time:

    Code (Text):

    $ g++ lorentz_subs.cpp -c
    $ g++ lorentz_main.cpp -c
    $ g++ lorentz_main.o lorentz_subs.o -o lorentz
    $
     
    Or if I already have lorentz_subs.o lying around, I just need to compile lorentz_main.cpp, and link it:

    Code (Text):

    $ g++ lorentz_main.cpp lorentz_subs.o -o lorentz
    $
     
    Or I can compile and link everything in one go:

    Code (Text):

    $ g++ lorentz_main.cpp lorentz_subs.cpp -o lorentz
    $
     
     
    Last edited: Aug 3, 2010
  13. Aug 3, 2010 #12
    Whoa....great catch on that #include... I guess the linker just complained about the first duplicate and gave up. Moving the functions around in the file would have given a further clue, which might not have been any clearer...

    In looking more carefully I notice that you have declarations in both main.h and main.c:

    struct DatabaseEntry;

    //Defines custom data structure to use to store information on each CD

    int numDatabaseEntries;
    struct DatabaseEntry * gDatabase;

    First, I think you should move your DatabaseEntry struct definition from myFunctions.c to main.h because the empty definition now in main.h may cause you trouble.

    Second, your compiler may be smart enough to know that numDatabaseEntries and gDatabase are the same entity but I would put "extern" in front of them in the header file to avoid ambiguities.

    All that said, I learned C before there was an ANSI so I probably haven't kept current on all the standard features and restrictions. If it works, use it...
     
  14. Aug 3, 2010 #13
    Wow, awesome last few posts here. I've just learnt a ton, thanks everyone :biggrin:
     
  15. Aug 3, 2010 #14

    rcgldr

    User Avatar
    Homework Helper

    Just a wild guess here, but wondering if you changed the declartion and actual function to:

    void NewEntry(void);

    if this would help. Perhaps the compiler is making conflicting definitions for NewEntry(..) in the case where it's only used (main.c) versus where its defined (myfunctions.c).
     
    Last edited: Aug 3, 2010
Share this great discussion with others via Reddit, Google+, Twitter, or Facebook