Compilation error - Most likely embarassingly easy, but I can't find what's wrong.

Discussion in 'C Programming' started by Sune, Oct 7, 2005.

  1. Sune

    Sune Guest

    Hi,

    previously I used Eclipse CDT for compiling my files just to get
    started with C and leave C++ behind. Now it's time to get a little more
    serious so I've moved my files to a new workplace and begun to use GNU
    Autotools. I'm sorry to say I'm new to gcc as well :(

    Now I get the most ridiculous compile error which I'm unable to solve.
    Can someone, please, help me with this? gcc output together with the
    files mentioned in the gcc error output follows below. It is about 50
    lines all in all, so I'm sure someone out there can find what's wrong
    pretty quickly.

    Thanks in advance anyone!
    Sune

    **************** Here is the gcc output *************
    [sune@localhost rsd2]$ make all
    make all-recursive
    make[1]: Entering directory `/home/sune/gnu-ws/rsd2'
    Making all in collections
    make[2]: Entering directory `/home/sune/gnu-ws/rsd2/collections'
    gcc -g -O2 -o collections_test DynamicString.o test_main.o
    test_main.o(.rodata+0x0): In function `t1':
    /home/sune/gnu-ws/rsd2/collections/test_main.c:12: multiple definition
    of `DynamicString_SUCCESS'
    DynamicString.o(.rodata+0x0):/home/sune/gnu-ws/rsd2/collections/DynamicString.c:10:
    first defined here
    test_main.o(.rodata+0x4): In function `t1':
    /home/sune/gnu-ws/rsd2/collections/test_main.c:12: multiple definition
    of `DynamicString_ERROR'
    DynamicString.o(.rodata+0x4):/home/sune/gnu-ws/rsd2/collections/DynamicString.c:10:
    first defined here
    collect2: ld returned 1 exit status
    make[2]: *** [collections_test] Error 1
    make[2]: Leaving directory `/home/sune/gnu-ws/rsd2/collections'
    make[1]: *** [all-recursive] Error 1
    make[1]: Leaving directory `/home/sune/gnu-ws/rsd2'
    make: *** [all] Error 2

    **************** Here is the beginning of my DynamicString.c file
    *************
    #include <string.h>
    #include <stdlib.h>
    #include <assert.h>

    #include "DynamicString.h"

    static const int FILE_ID = 0;

    inline void DynamicString_init( DynamicString* string_obj, int trace_id
    )
    {
    string_obj->stack_string[0] = '\0';
    string_obj->heap_string = 0;
    string_obj->string = 0;
    string_obj->size = 0;
    string_obj->capacity = DynamicString_stack_string_size;

    }

    **************** Here is the beginning of my DynamicString.h file
    *************
    #ifndef DYNAMICSTRING_H_
    #define DYNAMICSTRING_H_

    #include <stddef.h>

    #include "../config.h" // Don't worry about the relative path, I'll
    fix it...

    const int DynamicString_ERROR=0;
    const int DynamicString_SUCCESS=1;


    enum { DynamicString_stack_string_size = 256 };

    typedef struct DynamicString_
    {
    char stack_string[ DynamicString_stack_string_size ];
    char* heap_string;
    char* string;
    size_t size;
    size_t capacity;
    } DynamicString;

    **************** Here is the beginning of my test_main.c file
    *************
    #include <stdio.h>
    #include <string.h>

    #include "debug/Debug.h"
    #include "collections/DynamicString.h"

    int
    t1(int),t2(int),t3(int),t4(int),t5(int),t6(int),t7(int),t8(int),t9(int),t10(int);
    int (*func[])(int) = { t1,t2,t3,t4,t5,t6,t7,t8,t9,t10 };

    // Init
    int t1( int trace_id )
    {
    DynamicString string;
    DynamicString_init( &string, trace_id );
    return 1; // Can't fail!
    }
     
    Sune, Oct 7, 2005
    #1
    1. Advertising

  2. Sune

    pete Guest

    Sune wrote:

    > Debug.h


    What's that?

    > int
    > t1(int),t2(int),t3(int),t4(int),t5(int),
    > t6(int),t7(int),t8(int),t9(int),t10(int);


    What's that supposed to be?
    It looks like an attempt at plural prototypes (no such thing).

    --
    pete
     
    pete, Oct 7, 2005
    #2
    1. Advertising

  3. Re: Compilation error - Most likely embarassingly easy, but I can'tfind what's wrong.

    pete <> writes:
    > Sune wrote:

    [...]
    >> int
    >> t1(int),t2(int),t3(int),t4(int),t5(int),
    >> t6(int),t7(int),t8(int),t9(int),t10(int);

    >
    > What's that supposed to be?
    > It looks like an attempt at plural prototypes (no such thing).


    Actually, I think it's legal.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    We must do something. This is something. Therefore, we must do this.
     
    Keith Thompson, Oct 7, 2005
    #3
  4. Sune

    Sune Guest

    Hi,

    yes, it's legal. Maybe it looks strange because of the odd linefeeds
    added by Google.

    BRs
    /Sune
     
    Sune, Oct 7, 2005
    #4
  5. Re: Compilation error - Most likely embarassingly easy, but I can'tfind what's wrong.

    Sune wrote:
    > test_main.o(.rodata+0x0): In function `t1':
    > /home/sune/gnu-ws/rsd2/collections/test_main.c:12: multiple definition
    > of `DynamicString_SUCCESS'


    This is the kind of error one gets from defining objects in header files.


    > **************** Here is the beginning of my DynamicString.h file
    > *************
    > #ifndef DYNAMICSTRING_H_
    > #define DYNAMICSTRING_H_
    >
    > #include <stddef.h>
    >
    > #include "../config.h" // Don't worry about the relative path, I'll
    > fix it...
    >
    > const int DynamicString_ERROR=0;
    > const int DynamicString_SUCCESS=1;


    If you must have these in your header, you could
    #define DynamicString_ERROR 0
    #define DynamicString_SUCCESS 1

    Or, if you have an allergy to #defines (get over it), you might try
    enum {DynamicString_ERROR, DynamicString_SUCCESS};

    Or, if you positively insist on defining objects in your header,
    contrary to all common sense, add the 'static' qualifier.
    static const int DynamicString_ERROR=0;
    static const int DynamicString_SUCCESS=1;
     
    Martin Ambuhl, Oct 7, 2005
    #5
  6. Sune

    Sune Guest

    Hi,

    thanks, that was the problem.

    I want to have them (DynamicString_ERROR and DynamicString_SUCCESS) in
    my header accessible to clients so that clients of DynamicString can
    use them to test the outcome of a call to functions I didn't include in
    the code I pasted into my post.

    What would be a more proper way of doing this? (Just beginning to get
    into C you know)

    Thanks again
    /Sune
     
    Sune, Oct 7, 2005
    #6
  7. "Sune" <> writes:

    > Hi,
    >
    > Now I get the most ridiculous compile error which I'm unable to solve.
    > Can someone, please, help me with this? gcc output together with the
    > files mentioned in the gcc error output follows below. It is about 50
    > lines all in all, so I'm sure someone out there can find what's wrong
    > pretty quickly.


    > test_main.o(.rodata+0x0): In function `t1':
    > /home/sune/gnu-ws/rsd2/collections/test_main.c:12: multiple definition
    > of `DynamicString_SUCCESS'


    This means that the varible DynamicString_SUCCESS is *defined* in
    multiple places. The problem is that you *define* it in a header
    file that gets included in several translation units. The fix is
    to *declare* the varible in the header file, and then *define* it
    in only one translation unit.

    *Declare* means telling the complier that there exist a name
    'DynamicString_SUCCESS', which is *defined* somewhere else. If the
    definition is in some other translation unit, the compiler will
    let the linker resolv it.

    *Define* means *declare* and in addition restore some storage for
    the name.

    /* Examples (assume file scope) */
    extern int foo1; /* Declaration only */
    int foo2; /* Declaration and definition */
    int foo3 = 42; /* Declaration and definition */

    extern void foo4(void); /* Declaration only */
    void foo5(void); /* Declaration only */
    void foo6(void) { } /* Declaration and definition */
     
    Niklas Norrthon, Oct 7, 2005
    #7
  8. Sune

    pete Guest

    Re: Compilation error - Most likely embarassingly easy, but I can'tfind what's wrong.

    Keith Thompson wrote:
    >
    > pete <> writes:
    > > Sune wrote:

    > [...]
    > >> int
    > >> t1(int),t2(int),t3(int),t4(int),t5(int),
    > >> t6(int),t7(int),t8(int),t9(int),t10(int);

    > >
    > > What's that supposed to be?
    > > It looks like an attempt at plural prototypes (no such thing).

    >
    > Actually, I think it's legal.


    That's a new one on me.
    Thank you.

    --
    pete
     
    pete, Oct 7, 2005
    #8
  9. Sune

    Guest

    Sune wrote:
    > test_main.o(.rodata+0x0): In function `t1':
    > /home/sune/gnu-ws/rsd2/collections/test_main.c:12: multiple definition
    > of `DynamicString_SUCCESS'
    > DynamicString.o(.rodata+0x0):/home/sune/gnu-ws/rsd2/collections/DynamicString.c:10:
    > first defined here


    What this is saying is that it has found two objects, one in the
    compilation unit it calls DynamicString.o, and one in test_main.o which
    have the same name DynamicString_SUCCESS, and both visible externally!
    So, it is confused ... (similar error with DynamicString_Error later).

    > **************** Here is the beginning of my DynamicString.h file
    > *************
    > #ifndef DYNAMICSTRING_H_
    > #define DYNAMICSTRING_H_


    Okay this ensures that the contents are not included twice in any one
    compilation unit. That is irrelevant when compiling separate
    compilation units (gcc interprets each top level .c file, i.e. the ones
    on the command line, as a separate compilation unit).

    > const int DynamicString_ERROR=0;
    > const int DynamicString_SUCCESS=1;


    Now, these are declaring two variables DynamicString_ERROR and
    DynamicString_SUCCESS outside any functions (assuming the .h file is
    included outside any functions as you showed in the portion I deleted).
    Such declarations, by default, declare entities with external linkage:
    i.e. specify that all such entities (i.e. all entities with external
    linkage everywhere in the program, not only in the compilation unit)
    with the same name should refer to the same entity. So, they have the
    same type, address etc., and changing the value of any of them (if they
    can be changed) should change all with the same name. The compiler is
    not required to check that you do not violate this, but as you saw, it
    certainly can.

    However, they have been initialized: this changes them from mere
    declarations into definitions! Which means, you are instructing the
    compiler to actual create such objects in the compilation unit.

    So, now, when you include this in multiple compilation units, what is
    the compiler supposed to do? The external linkage is forcing the
    interpretation that there should only be one entity with each name,
    whereas the definition is forcing one object per compilation unit in
    which the inclusion takes place.

    So, what options do you have other than having only one compilation
    unit? Well, here are a few:

    a) Use #define instead of an object. This just defines a new
    preprocessor token which behaves identically to the number in the
    compilation stage. So, it is not scoped (well, you are at global
    scope, so that is not terribly important, except you cannot hide it by
    local definitions), has no name space (so you cannot use it as a label
    or tag etc.), and since you don't create an object, you cannot take its
    address. You however get a constant expression which can be used in
    places where an object evaluation is not allowed.

    b) Not initialize the variable and declare it as an extern (If you do
    not put the extern, initialization to 0 is assumed if no other
    declaration in the same compilation unit defines it). In this case,
    you can make sure it gets declared in exactly one compilation unit
    somehow. In that case, no other compilation unit knows what value the
    object has, possibly loosing optimization opportunities, but otherwise
    behaves identically.

    c) Declare it as static. This gives it `internal' linkage: that is it
    is the same as every other entity with the same name and internal
    linkage in the compilation unit, but distinct from every object or
    function of the same name in other compilation units. This takes up
    space in each compilation unit, but for such small amount of stuff,
    that presumably does not matter. Two things to note: (1) an extern
    declaration where a declaration with internal linkage is visible (i.e.
    in scope and not hidden), provides a further declaration of the entity
    with internal linkage (and thus refers to the same entity), and does
    not declare it with external linkage. (2) If you do declare the same
    name with both internal and external linkage in the same translation
    unit, you get undefined behaviour.
    (C++ and C differ subtly for const objects at global scope with neither
    extern nor static specified: I am obviously giving the C rules here)

    d) As you did below
    >
    >
    > enum { DynamicString_stack_string_size = 256 };


    This defines a new token (not a preprocessor token) which is still an
    integral constant expression. Such identifiers, however, do not refer
    to objects, and hence you cannot take their address, but are scoped and
    obey name spaces.
     
    , Oct 7, 2005
    #9
  10. Sune

    Sune Guest

    Hi,

    thanks for a real good explanation. I have changed it into external
    linking with 'extern' and it works fine. I prefer objects in order to
    avoid magic numbers during debugging.

    BRs
    Sune
     
    Sune, Oct 7, 2005
    #10
  11. Re: Compilation error - Most likely embarassingly easy, but I can'tfind what's wrong.

    Sune wrote without providing context:
    > Hi,
    >
    > thanks, that was the problem.
    >
    > I want to have them (DynamicString_ERROR and DynamicString_SUCCESS) in
    > my header accessible to clients so that clients of DynamicString can
    > use them to test the outcome of a call to functions I didn't include in
    > the code I pasted into my post.


    Over and over the instructions have been posted for properly replying
    when using the broken googlegroups interface. Always follow a newsgroup
    before posting. This makes sure that you know what is acceptable in a
    newsgroup, but also would lead to knowing how to find the FAQ and how to
    use googlegroups properly.

    You don't need _objects_ accessible, but only values.

    > What would be a more proper way of doing this? (Just beginning to get
    > into C you know)


    Exactly as I showed you in the post to which you are replying:

    > If you must have these in your header, you could
    > #define DynamicString_ERROR 0
    > #define DynamicString_SUCCESS 1
    >
    > Or, if you have an allergy to #defines (get over it), you might try
    > enum {DynamicString_ERROR, DynamicString_SUCCESS};
    >
    > Or, if you positively insist on defining objects in your header, contrary to all common sense, add the 'static' qualifier.
    > static const int DynamicString_ERROR=0;
    > static const int DynamicString_SUCCESS=1;
     
    Martin Ambuhl, Oct 7, 2005
    #11
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    2
    Views:
    364
  2. sam
    Replies:
    10
    Views:
    553
    Mabden
    May 13, 2004
  3. Ken Guest
    Replies:
    2
    Views:
    304
    Ken Guest
    Jan 6, 2006
  4. Adam Cohen
    Replies:
    1
    Views:
    140
    Greg Willits
    Jun 14, 2010
  5. Ziliang Chen
    Replies:
    3
    Views:
    169
    Ziliang Chen
    Feb 22, 2013
Loading...

Share This Page