Modul einbinden > Linker error
-
Hallo zusammen,
ich habe ein problem mit dem einbinden eines moduls in meine hauptfunktion. Hier mal der Quellcode:
Hier die Main funktion main.cpp:# include <iostream>
# include "wieoft.h"using namespace std;
int main ()
{
cout << "Dies ist der: " << wieoft ()<< ". Aufruf der Funktion \"wieoft\"." << endl;
cout << "Dies ist der: " << wieoft ()<< ". Aufruf der Funktion \"wieoft\"." << endl;
cout << "Dies ist der: " << wieoft ()<< ". Aufruf der Funktion \"wieoft\"." << endl;
cout << "Dies ist der: " << wieoft ()<< ". Aufruf der Funktion \"wieoft\"." << endl;
cout << "Dies ist der: " << wieoft ()<< ". Aufruf der Funktion \"wieoft\"." << endl;
cout << "Dies ist der: " << wieoft ()<< ". Aufruf der Funktion \"wieoft\"." << endl;
cout << "Dies ist der: " << wieoft ()<< ". Aufruf der Funktion \"wieoft\"." << endl;
}Modul wieoft.cpp
# include <iostream>
using namespace std;int wieoft ()
{
static int a=1;
return (a++);
}und die dazugehörige header datei wieoft.h:
int wieoft (void);
wenn ich das kompiliere bekomme ich immer einen linker error vom compiler zurück.
[linker error] undefined referece to 'wieoft()'
ich hoffe ihr könnt mir helfen,
greetz
Patrick
-
Hast du die wieoft.cpp Datei eigentlich mitkompiliert und gelinkt?
Besserer Code:
//wieoft.hpp namespace { int wieoft(); }//wieoft.cpp #include "wieoft.hpp" namespace { int wieoft() { static int i=0; return ++i; } }#include <iostream> #include "wieoft.hpp" int main(int argc, char **argv) { for (int i=0;i<10;++i) std::cout<<"Dies ist der: " << wieoft ()<< ". Aufruf der Funktion \"wieoft\".\n"; return EXIT_SUCCESS; };
-
Das "Modul" nennt sich übrigens Header.
-
Sorry wenn sich die fragen jetzt vielleicht n bissl blöd anhören, aber ich fange gerade erst mit programmieren an.
-Was genau meinst du mit gelink? Ich habe versucht die wieoft.cpp zu kompilieren aber da bekomme ich immer die Fehlermeldung:
[Linker error] undefined reference to `WinMain@16'
die mir leider überhaupt nichts sagt.
-Es ist super nett von Dir den verbesserten Code zu posten aber irgendwie versteh ich das Meiste aus der main.cpp nicht
.
Habe mit einem Lehrbuch angefangen und mich jetzt seit Tage an diesem Problem festgebissen und daher auch nicht weiter gelesen. Kontrollstrukturen kommen z.B. erst noch. Die Sternchen in der Übergabe der Main.cpp sagen mir leider auch garnichts.
Trotzdem Danke für Deine Mühe
Patrick
-
GPC schrieb:
Besserer Code:
Hast du das eigentlich mal ausprobiert? Sieht oberflächlich gesehen aus als hättest du genau den gleichen Linker-Error eleganter nachgebaut

@Segafredo
Welchen Compiler/welche IDE benutzt du?Segafredo schrieb:
-Es ist super nett von Dir den verbesserten Code zu posten aber irgendwie versteh ich das Meiste aus der main.cpp nicht
.Hat im Prinzip den selben Effekt wie dein Code. Die Parameter und das return kannst du im Grunde weglassen, dann bleibt nur noch die Schleife statt zigmal die selbe Codezeile dahinzupasten.
-
-Was genau meinst du mit gelink? Ich habe versucht die wieoft.cpp zu kompilieren aber da bekomme ich immer die Fehlermeldung:
[Linker error] undefined reference to `WinMain@16'
die mir leider überhaupt nichts sagt.Der Punkt ist, dass du deine main.cpp und die wieoft.cpp gleichzeitig in einem Schritt kompilieren sollst, dann findet er auch die main Methode, und zwar in main.cpp, linken ist einfach die Erstellung einer ausführbaren Datei aus deinem Code (und evtl. verwendeten Bibliotheken).
Hast du das eigentlich mal ausprobiert? Sieht oberflächlich gesehen aus als hättest du genau den gleichen Linker-Error eleganter nachgebaut

Nein, hab's nur so hingeschrieben, Verwendung von anonymen namespace sollte Problem eliminiert haben. Werd's gleich mal ausprobieren.
das return kannst du im Grunde weglassen
Bloß weil's deinen Compiler nicht juckt, ist es noch lange nicht gut. Ans Ende von main gehört ein return! Gerade Anfängern sollte man das eintrichtern. Sonst stehen sie in 3 Jahren hier und schreiben void main oder int main ohne return.
-
Hast du das eigentlich mal ausprobiert? Sieht oberflächlich gesehen aus als hättest du genau den gleichen Linker-Error eleganter nachgebaut

Nein, hab's nur so hingeschrieben, Verwendung von anonymen namespace sollte Problem eliminiert haben. Werd's gleich mal ausprobieren.
mit anonymen namespaces kann das niemals funktionieren - der sinn von solchen namespaces ist ja gerade, dass sie in jeder ÜE einen anderen internen namen haben. d.h. alles was du in annonymen namespaces deklarierst, muss auch in der ÜE, in der es verwendet wird, definiert werden (und diese definition kolliert mit keiner definition in einer anderen ÜE. erst so wird static für gloable bezeichner überflüssig.
GPC schrieb:
das return kannst du im Grunde weglassen
Bloß weil's deinen Compiler nicht juckt, ist es noch lange nicht gut. Ans Ende von main gehört ein return! Gerade Anfängern sollte man das eintrichtern. Sonst stehen sie in 3 Jahren hier und schreiben void main oder int main ohne return.
main ist keine normale funktion und ein return statement ist dort nicht notwendig. allerdings gab es keinen grund das zu erwähnen. es ist schliesslich niemals schlechter stil, dort ein return stehen zu haben.
-
@camper, finix
Stimmt, ihr habt recht, hab mich vertan. Man kann die Implementierung aber auch in die hpp Datei packen und gut is.
-
GPC schrieb:
Hast du das eigentlich mal ausprobiert? Sieht oberflächlich gesehen aus als hättest du genau den gleichen Linker-Error eleganter nachgebaut

Nein, hab's nur so hingeschrieben, Verwendung von anonymen namespace sollte Problem eliminiert haben. Werd's gleich mal ausprobieren.
Internal linkage?
das return kannst du im Grunde weglassen
Bloß weil's deinen Compiler nicht juckt, ist es noch lange nicht gut. Ans Ende von main gehört ein return! Gerade Anfängern sollte man das eintrichtern. Sonst stehen sie in 3 Jahren hier und schreiben void main oder int main ohne return.[/quote]
Soweit ich mich entsinne juckt's den Standard auch nicht wirklich - und meist kann ich mit dem impliziten "return 0;" leben. Aber du hast Recht, gerade Anfängern sollte man die ganze Sache nicht verkomplizieren.Edit: oh wie lahm!

Aber noch was:GPC schrieb:
@camper, finix
Stimmt, ihr habt recht, hab mich vertan. Man kann die Implementierung aber auch in die hpp Datei packen und gut is.Erstell mal eine weitere ÜE in der du die wieoft-Funktion zusätzlich testest...
-
Hi zusammen,
danke für die vielen Antworten.
@finix
Die umgebung ist dev-c++
@GPC
wie kann ich denn die main.cpp und die wieoft.cpp gleichzeitig in einem Schritt kompilieren?
greetz
Patrick
-
Gar nicht - aus jeder CPP erzeugt der Compiler eine eigene Objektdatei. Und der Linker benötigt dann ALLE relevanten Objektdateien, wenn er das fertige Programm erzeugen will.
-
Jetzt verstehe ich gar nichts mehr

der eine schreibt, die oben genannte Fehlermeldung besagt, das ich beiden .cpp´s zusammen kompilieren muss, der andere sagt ich das nicht machen soll.
Hmmmm
Leute ihr verwirrt mich.
greetz
Patric++k
-
Ich glaube, jetzt habe ich mich sogar selber verwirrt

Also: Der Compiler bearbeitet immer nur eine CPP zur selben Zeit, allerdings kannst du ihm sagen, daß er hintereinander mehrere Dateien compilieren und dann linken soll (Visual Studio macht das afaik selber, dem GCC mußt du die Namen aller Quelldateien als Parameter übergeben).
-
Visual studio merkt gar nix selber ^^
der MS VC++ compiler nutzt genau so make files ... nur natuerlich mit eigener syntax und mit eigenem make (nmake). Wer ja erniedrigend, wenn MS sich an nen Standard halten muesst ^^
Deine IDE's erzeugen in der Regel deine makefiles. Die cpp dateien werden als Quelle in der Projectdatei (fuer jede IDE unnerschiedlich) mit angegeben ... und vorm eigentlichen "compilerlauf" baut die IDE nen Makefile. In dem makefile steht drinne, welche cpp dateien "compileirt" werden sollen ....
Das macht der VS compiler genau so wie das Borland Teil, wie der QT Builder, wie KDevelop, wie devcpp wie Code::Blocks.beim eigentlichen compileieren wird nur noch das makefile abgearbeitet.
Das was umgangssprachlich als compileieren / uebersetzen bezeichnet wird, sind eigentlich 3 Sachen. der preprozessor, compiler, linkerrichtig:
der compiler betrachtet nur eine cpp Datei aufs mal. Aber durch die includes, (job des Preprozessors, die definitionen wirklich in das temp zu compilierende teil mit reinzuschreiben) kennt der compiler an der stelle Klassen, variablen funktionen etc, die nicht in der cpp datei definiert sind ...
Er weiss nur dass es sie gibt. Deshalb generiert er Platzhalter dafuer, die sogenannten Symbole. Das ergebnis ist die obj datei, in der datei liegen quasi die codefragmente als binaercode vor, mit verweisen/symbole auf zeugs was er in der obj datei noch nicht kennen kann.Zum schluss kommt nu der linker(binder), der nimmt die binaercode fragmente, setzt sie an die richtige stelle, baut den executable header etc zusammen, und ersetzt die Verweise/Symbole durch die richtige Adresse innerhalb des fertigen executables ....
wenn du beispielsweise ne .h datei einbindest, nen object verwendest, aber die dazugehoerige .lib(.a) (iss nur eine (mit ar unter Linux ) komprimierte sammlung von .obj dateien) nicht dazu linkst, kann der linker in der obj datei das symbol nicht aufloesen, und es kommt zu dem beruechtigten "unresolved symbols" meldung.Hoffe iss einigermassen verstaendlich erklaert ^^ (und viele sache unzulaessig vereinfacht)
Ciao ...
-
RHBaum schrieb:
Visual studio merkt gar nix selber ^^
der MS VC++ compiler nutzt genau so make files ... nur natuerlich mit eigener syntax und mit eigenem make (nmake). Wer ja erniedrigend, wenn MS sich an nen Standard halten muesst ^^
Sorry, wenn ich mich zu kurz gefasst habe - was ich mit "Visual Studio macht das selber" meinte, war, daß die IDE sich das nötige Makefile zusammenbaut, um alle benötigten Quelldateien deines Projektes neu compilieren zu könne, wenn es nötig ist.