gnu c frage: 'multiple definition of ...'

  • hallo!

    ich glaube ich habe schon zu lange nicht mehr c programmiert.. heute wollte ich ein kleines tool schreiben, das mit farbformatierung zu tun hat. ich habe es dann auch durch ein paar unschöne tricks zum laufen bekommen, würde aber gerne wissen, warum es so nicht funktioniert:

    ich habe 4 dateien:

    test.c, welches nur test.h inkludiert: in test.c wird in main() die methode colprintf() aus colprintf.c aufgerufen, außerdem benötigt es konstanten aus colprintf.h
    test.h, welches stdio.h, stdlib.h und colprintf.h inkludiert
    colprintf.c, welches nur colprintf.h inkludiert: enthält die methode colprintf()
    colprintf.h, welches stdio.h, stdlib.h inkludiert: enthält deklaration für colprintf und einige konstanten

    mein makefile sieht so aus:

    Code
    all: test colprintf
    	gcc -o test test.o colprintf.o
    colprintf: colprintf.c colprintf.h
    	gcc -Wall -ansi -g -pedantic -c colprintf.c
    test: test.c test.h
    	gcc -Wall -ansi -g -pedantic -c test.c

    ich sage 'make' und bekomme:

    Code
    colprintf.o(.data+0x0): In function `colprintf':
    /home/mj/programming/c/colprintf/colprintf.c:7: multiple definition of `COLOR_SPECIAL_RESET'
    .
    . (das gleiche für jede Konstante)
    .
    test.o(.data+0x0):/home/mj/programming/c/colprintf/test.c:4: first defined here
    collect2: ld returned 1 exit status
    make: *** [all] Error 1

    habe ich da irgendeinen anfängerfehler gemacht, oder ist das etwas subtileres?

    lg michi

  • Die Konstanten sind mit "const typ COLOR_SPECIAL_RESET = anfangswert" oder ähnlichem deklariert?
    Dann ist diese Deklaration gleichzeitig eine Definition. D.h. es wird hier nicht nur dem Compiler gesagt "hey, es gibt eine Variable mit diesem Namen", sondern gleichzeitig auch dem Linker "lege bitte Speicherplatz für diese Variable an". Du definierst also sowohl in test.c als auch in colprintf.c eine solche Variable, und der Linker beschwert sich schließlich, daß er zwei Objektfiles zusammenlinken soll, die "verschiedene" Variablen mit dem selben Namen enthalten. Das geht so nicht.

    Jedes Objekt muß in C an genau einer Stelle definiert sein, deklarieren darfst du alles mehrmals; die Deklarationen beziehen sich dann alle auf das selbe Objekt. In deinem Programm kannst du das folgendermaßen erreichen: Ändere alle deine Deklarationen in den Header-Files auf extern-Deklarationen, d.h. schreibe das Schlüsselwort "extern" davor und tu die Initialisierung weg. Das sagt dem Linker, daß es irgendwo eine Variable mit diesem Namen geben wird, auf die sich dieser Name beziehen soll.
    Dann definierst du irgendwo an einer Stelle in einem C-File die Variablen wie zuvor, ohne extern und mit Initialisierung. Das kann in einem deiner bestehenden C-Files passieren, oder aber auch in einer neuen Datei "vardefs.c" oder so. Die mußt du dann natürlich auch kompilieren und zum Rest des Programms dazulinken.

    Ooooder du änderst die Konstanten auf Preprocessor-Konstanten, also mit #define definierte. Hat gewisse Vor- aber auch Nachteile.

    So, ich hoffe, ich habe dein Problem von der Ferne richtig diagnostiziert, und daß ich die Situation auch einigermaßen verständlich erklärt habe. Viel Erfolg! :thumb:

    *plantsch*

  • Zitat von michi204
    Code
    colprintf.o(.data+0x0): In function `colprintf':
    /home/mj/programming/c/colprintf/colprintf.c:7: multiple definition of `COLOR_SPECIAL_RESET'
    .
    . (das gleiche für jede Konstante)
    .
    test.o(.data+0x0):/home/mj/programming/c/colprintf/test.c:4: first defined here
    collect2: ld returned 1 exit status
    make: *** [all] Error 1


    ohne den code zu kennen wird dir wohl niemand etwas konkreteres sagen koennen als
    der compiler. du hast diese konstanten oefters definiert.

    lg
    amok

  • Ich nehme an, dass die Konstanten in colprintf.h nicht extern deklariert sind:

    Code
    #ifndef _COLPRINTF_H
        #define _COLPRINTF_H
    
       /* [...] */
    
        extern int COLOR_SPECIAL_RESET;
    
       /* [...] */
    
        #endif /* _COLPRINTF_H */



    Diese Konstanten müssen dann in einem (1) C File definiert werden:

    Code
    int COLOR_SPECIAL_RESET = 0;
       /* [...] */



    Aber besser wäre es wohl, du würdest den Präprozessor verwenden:

    Code
    #ifndef _COLPRINTF_H
         #define _COLPRINTF_H
    
        /* [...] */
    
       #define COLOR_SPECIAL_RESET 0;
    
        /* [...] */
    
         #endif /* _COLPRINTF_H */



    Dann kann es dir nämlich nicht mehr passieren, dass der Linker sich über Nameclashes bei den globalen Variablen aufregt.

  • hallo!

    danke für eure raschen antworten! ihr habt alle recht: die konstanten waren weder extern noch #define, sondern nur const char* =...

    der grund, warum ich nicht den ganzen code gepostet habe, ist, dass ich eher ein strukturelles problem vermutet hatte...

    danke!

    michi

  • Zitat von djmaecki
    Code
    #ifndef _COLPRINTF_H
        #define _COLPRINTF_H
    
       /* [...] */
     
        #endif /* _COLPRINTF_H */

    Dann kann es dir nämlich nicht mehr passieren, dass der Linker sich über Nameclashes bei den globalen Variablen aufregt.

    auch auf die gefahr hin, paedantisch zu wirken, muss ich doch einwenden, dass du im code beispiel durch die verwendung des identifiers _COLPRINTF_H einen schlechten tip gibst.

    der standard reserviert die nutzung von identifieren die mit _<grossbuchstabe> sowie __ beginnen (ISO/IEC 9899:1999 7.1.3). auch wenn es hier in diesem fall keine gefahr ist sollte man genau sowas nicht verwenden um nameclashes mit zukuenftigen library versionen zu verhindern.

    lg
    amok

  • Zitat von amok

    der standard reserviert die nutzung von identifieren die mit _<grossbuchstabe> sowie __ beginnen (ISO/IEC 9899:1999 7.1.3). auch wenn es hier in diesem fall keine gefahr ist sollte man genau sowas nicht verwenden um nameclashes mit zukuenftigen library versionen zu verhindern.


    Aha, C99 hab ich mir noch nicht reingezogen, bin eher C89 gewöhnt ;-). Oder war das damals auch schon so? Man lernt ja nie aus.

  • Zitat von djmaecki

    Aha, C99 hab ich mir noch nicht reingezogen, bin eher C89 gewöhnt ;-). Oder war das damals auch schon so? Man lernt ja nie aus.

    war damals genauso, nur die nummerierung war anders :)

    lg
    amok

Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!