multiple definition of function (c, gcc, make)
-
Erstmal guten morgen meinerseits,
habe ein Problem beim linken eines Programmes: Die Funktion print_player2 wird mehrmals definiert.Wo habe ich hier einen Fehler gemacht? Die Header sind ja durch #ifndef gegen mehrmaliges inkludieren geschützt, also muss der Fehler im Makefile liegen.
Evtl. ist in beiden Dateien - main.o und player.o - die Funktion definiert? Wie löse ich das Problem?Ich benutze MinGW.
Danke für die Hilfe
$ make gcc -Wall -pedantic -ansi -o main.o -c main.c gcc -Wall -pedantic -ansi -o player.o -c player.c gcc -Wall -pedantic -asni -o launch.exe main.o player.o player.o:player.c:(.text+0x29): multiple definition of 'print_player2' main.o:main.c:(.text+0x29): first definition here collect2.exe: error: ld returned 1 exit status make: *** [launch.exe] Error 1
/* main.c */ #include "dependencies.h" int main(void) { struct player p; p.name = "Max"; print_player(&p); print_player2(&p); return EXIT_SUCCESS; } /* dependencies.h */ #ifndef ENOX_DEPENDENCIES_H #define ENOX_DEPENDENCIES_H #include <stdio.h> #include <stdlib.h> #include "player.h" #endif /* player.c */ #include "player.h" void print_player(struct player *p) { printf("name: %s\n", p->name); } /* player.h */ #ifndef ENOX_PLAYER_H #define ENOX_PLAYER_H #include <stdio.h> struct player { const char *name; }; void print_player(struct player*); void print_player2(struct player *p) { printf("name: %s match\n", p->name); } #endif
Das Makefile:
LINK_TARGET = launch.exe OBJS = main.o player.o REBUILDABLES = $(OBJS) $(LINK_TARGET) CC = gcc CFLAGS = -Wall -pedantic -ansi .PHONY : all all : $(LINK_TARGET) .PHONY : clean clean : -rm $(REBUILDABLES) $(LINK_TARGET) : $(OBJS) $(CC) $(CFLAGS) -o $@ $^ %.o : %.c $(CC) $(CFLAGS) -o $@ -c $<
-
Der Linker beschwert sich, da
print_player2
in zwei verschiedenen sog. „translation units“ definiert wurde. Sowohlplayer.c
als auchmain.c
inkludierenplayer.h
.
„Include guards“ helfen nur bei mehrmaligen Inkludieren eines Headers in einer TU.
Entweder du definierst diese Funktion inplayer.c
oder verwendeststatic
. Dadurch hat sie „internal linkage“, d.h. die Funktionsdefinition ist nur in der jeweiligen TU sichtbar.
-
Funktionsdefinitionen in Headerdateien sind ganz ganz selten nötig. Noch seltener.
EinGast schrieb:
... oder verwendest
static
. Dadurch hat sie „internal linkage“, d.h. die Funktionsdefinition ist nur in der jeweiligen TU sichtbar.Dann ist die Funktion allerdings mehrmals im ausführbaren Programm vorhanden.
-
EinGast schrieb:
Der Linker beschwert sich, da
print_player2
in zwei verschiedenen sog. „translation units“ definiert wurde. Sowohlplayer.c
als auchmain.c
inkludierenplayer.h
.
„Include guards“ helfen nur bei mehrmaligen Inkludieren eines Headers in einer TU.
Entweder du definierst diese Funktion inplayer.c
oder verwendeststatic
. Dadurch hat sie „internal linkage“, d.h. die Funktionsdefinition ist nur in der jeweiligen TU sichtbar.Danke für die schnelle Antwort! Frage mich warum ich die Funktion im Header hatte o.O
-
EinGast schrieb:
Entweder du definierst diese Funktion in
player.c
oder verwendeststatic
. Dadurch hat sie „internal linkage“, d.h. die Funktionsdefinition ist nur in der jeweiligen TU sichtbar.Wie DirkB schon beschrieben hat taucht die Funktion dann aber mehrfach im Speicher auf, was man nicht wirklich haben moechte.
Du hast aber eine Variante vergessen. Anstelle vonstatic
kann man auchinline
schreiben. Dann wird der Code der Funktion vom Compiler an die aufrufende Stelle kopert (also der Aufruf wird mit dem Funktionscode ersetzt). Das ist besonders dann Wertvoll, wenn man mit viel Abstraktion arbeitet, am Ende nur eine kleine Funktion hat (1-5 Zeilen) und sich nicht einen teuren Sprung leisten moechte.
-
inline
habe ich nicht (oder absichtlich) aufgrund der CFLAGS vergessen.inline
ist ein wenig komplexer als du das so erklärt hast.
Dassstatic
die nicht empfehlenswerte Variante ist, hätte ich allerdings extra erwähnen sollen, da das nicht wirklich offensichtlich ist. Nun ja, das habt ihr ja nun erledigt.
-
EinGast schrieb:
inline
habe ich nicht (oder absichtlich) aufgrund der CFLAGS vergessen.inline
ist ein wenig komplexer als du das so erklärt hast.Koennst du bitte einmal auf die Details eingehen? Ich verwende regelmaessig inline und habe bisher leider noch nichts von diesem Problem gehoert und/oder gelesen. Auf die Schnelle konnte ich leider auch keinen Hinweis auf wirkliche Probleme finden. Dazu habe ich sowohl bei [1] und [2] den Verweis darauf gefunden, dass man sie in gewissen Situationen nutzen soll (anstelle von Makros). Generell nutze ich sie auch in diesen Rahmen regelmaessig.
Fuer eine genauere Erklaerung waere ich dir dankbar.
[1] http://www.cplusplus.com/forum/articles/20600/
[2] http://embeddedgurus.com/barr-code/2011/03/do-inline-function-bodies-belong-in-c-header-files/
-
inline
gibt es nicht in ISO C90 (und das ist anscheinend für enox sehr wichtig).inline
hat unterschiedliche Semantiken in ISO C99, dem GNU-Dialekt von ISO C90 und C++: http://stackoverflow.com/a/216546 oder http://www.greenend.org.uk/rjk/tech/inline.html. Dein Vorschlaginline
stattstatic
zu schreiben ist also nicht portabel und führt zu einem Linker-Fehler in Standard-C.inline
ist außerdem nur ein Hinweis. Einige weniger populäre Compiler (u.a TCC) ignorieren diesen oder können diesen sogar immer befolgen, auch wenn es negative Auswirkungen auf die Größe der Funktion/des Kompilats hat. Compiler-Optionen können auch Einfluss darauf ausüben, z.B. würde in diesem Fall GCC den Hinweis nicht beachten.(Am Rande: Einem gut optimierenden Compiler ist es eh egal, ob da jetzt
static
oderstatic inline
steht. So wie ein gut optimierender Linker auch weiß, wie er mit unbenutzten oder doppelten Funktionen umzugehen hat.)