Problem beim "auslagern" von Funktionen...
-
hallo Rille hier,
Als ich mein erstes Programm zuendegeschrieben hatte, hat mich einer meiner freunde ausgelacht und gemeint "1a-spaghetti-text", als der meinen quellcode sah.
Nun wie dem auch sei, einige programme später steh ich hier wieder vor dem selben problem nur mit einem unterschied: ich weis jetzt, oder besser lerne es gerade, mit mit funktionen umzugehen. allerdings ändert sich nicht wirklich viel an der übersichtlichkeit meiner geistigen ergüsse. also dachte ich mir, ich kann ja die funktionen in verschiedene datein stecken. wie mache ich das am dümmsten und gibts irgendetwas wichtiges was man dabei beachten muss?
für konstruktive vorschläge bedanke ich mich schonmal im voraus
mfg rille
-
Dieser Thread wurde von Moderator/in SideWinder aus dem Forum DOS und Win32-Konsole in das Forum ANSI C verschoben.
Im Zweifelsfall bitte auch folgende Hinweise beachten:
C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?Dieses Posting wurde automatisch erzeugt.
-
Hallo,
löbliches Vorhaben, mehr Übersicht in deinen Code zu bringen. Ein Beispiel:
//foo.h #ifndef FOO_H #define FOO_H extern void bar(); #endif //FOO_H
//foo.c #include "foo.h" #include <stdio.h> void bar() { puts("Hallo Welt"); }
//main.c #include "foo.h" int main() { bar(); //Ausgabe, oh je oh je: Hallo Welt ;-) return 0; }
EDIT: Nicht vergessen, foo.c mitzukompilieren
MfG
GPC
-
"extern" bei Funktionen in einer Header zu schreiben bringt nichts. Kannst du genauso gut rauslassen.
-
also muss ich jeder neuen *.cpp-file auch noch ne *.h spendieren, wobei in der headerdatei nur die Prototypen stehen und die funktion selber in der *.cpp. hab ich das so richtig verstanden?
danke für die schnelle antwort.
-
mmmh also ich hab noch ne kleine frage diesbezüglich.
ich hab jetzt ne funct.h und ne funct.cpp erstellt. in der funct.h hab ich die prototypen rein und in die funct.cpp die funktionen. jetzt bekomme ich aber zwei fehlermeldungen die da lauten:
funct.obj : error LNK2005: "void __cdecl gotoxy(int,int)" (?gotoxy@@YAXHH@Z) bereits in Passwordmanager.obj definiert
funct.obj : error LNK2005: "void __cdecl setcursor(int)" (?setcursor@@YAXH@Z) bereits in Passwordmanager.obj definiertwas sollen mir diese fehlermeldungen sagen? zwar kann ich daraus erkennen das es um den gotoxy()- und den setcursor()-befehl geht und das diese beiden befehle schonmal definiert wurden aber ich hab keine ahnung wie ich das lösen soll?
P.S.: ich hab ne selbstgemachte header-datei mit dem namen selfmade.h, da sind die befehle unter anderem drin(ich hab die aus der col_conio und für meine bedürfnisse umgeschrieben und dann in den include-ordner von .Net geschmissen). ich hab halt allerdings keine zugehörige selfmade.cpp. ist das der fehler? weil so ging die selfmade.h vorher ja einwandfrei.
-
also ich hab jetzt die gotoxy() und die setcursor()-funktionen mit in die funct.h/.cpp eingefügt und es geht jetzt, aber das is halt nur ne notlösung.
-
Du mußt ganz am Anfang in Deine Headerdatei
#ifndef FUNCT_H #define FUNCT_H
und am Ende
#endif
schreiben.
Der Grund ist folgender: Wenn Du die Datei funct.h an mehreren Stellen per #include einbaust, ist das für den Compiler so, als würdest Du die enthaltenen Funktionen mehrmals deklarieren. Der #include-Befehl macht nämlich nichts anderes als den Quelltext aus der angegebenen H-Datei in die Datei zu kopieren, wo das #include vorkommt.
Wenn mein Projekt also folgendermaßen aussieht:
Main.cpp:
#include "Header.h" void main () { ... }
Header.h:
const int KONSTANTE=5; void Funktion ();
Header.cpp:
#include "Header.h" void Funktion () { ... }
dann macht der Compiler daraus etwas, was Du Dir so vorstellen kannst:
Main.cpp:
const int KONSTANTE=5; void Funktion (); void main () { ... }
Header.cpp:
const int KONSTANTE=5; void Funktion (); void Funktion () { ... }
was dann zu den zwei OBJ-Dateien wird, welche wiederum zu einer Exe-Datei verarbeitet werden. Und wie Du siehst, werden hier die Funktion und die Konstante zweimal deklariert. Deshalb muß die H-Datei folgendermaßen aussehen:
#ifndef HEADER_H #define HEADER_H const int KONSTANTE=5; void Funktion (); #endif
Wenn er diese Datei das erste Mal inkludiert, arbeitet er die erste Zeile ab: "Wenn HEADER_H nicht definiert ist". Das ist ähnlich einer if-Anweisung. Er geht also in die Bedingung rein und definiert HEADER_H. Das heißt, wenn er das nächste Mal durch den Quellcode dieser Datei geht, weil sie mit #include eingebunden wurde, stößt er wieder auf die Abfrage #ifndef HEADER_H und geht diesmal nicht mehr weiter, sondern springt gleich an das #endif, da ja HEADER_H schon definiert und die Bedingung damit nicht erfüllt ist.
Alles klar? Wenn nicht, ist auch egal. Merk Dir einfach daß jede(!) Headerdatei am Anfang ein
#ifndef IRGENDEIN_VON_DIR_ERDACHTER_NAME #define IRGENDEIN_VON_DIR_ERDACHTER_NAME
und am Ende ein
#endif
haben soll. (Natürlich darf derselbe IRGENDEIN_VON_DIR_ERDACHTER_NAME nicht in zwei verschiedenen Headern stehen. Du kannst #ifndef HEADER_H also nicht in "Header.h" und in "Funktionen.h" schreiben, sondern "Funktionen.h" muß etwas anderes bekommen, z.B. #ifndef FUNKTIONEN_H, aber das sollte eigentlich logisch sein.)
-
@NES: Was du da erzählst, ist (sorry) großer Käse. Include-Guards nützen nur etwas, wenn ein Header in der selben Übersetzungseinheit doppelt vorkommt - der Linker bekommt von ihrer Existenz noch nicht einmal etwas mit. Und bei Funktionsprototypen und Konstanten (die sind per Default statisch gelinkt) ist es dem Linker sowieso egal, wie oft und wo sie erwähnt werden.
-
@NES: Was du da erzählst, ist (sorry) großer Käse. Include-Guards nützen nur etwas, wenn ein Header in der selben Übersetzungseinheit doppelt vorkommt - der Linker bekommt von ihrer Existenz noch nicht einmal etwas mit. Und bei Funktionsprototypen und Konstanten (die sind per Default statisch gelinkt) ist es dem Linker sowieso egal, wie oft und wo sie erwähnt werden.
Gut, das mit den Funktionsprototypen stimmt. Und Konstanten können natürlich überall erwähnt werden, aber deklariert werden dürfen sie nur einmal. Das heißt, wenn in einer H-Datei eine Konstante deklariert wird und man ruft diese H-Datei zweimal mit #include auf (und sie hat keine Include-Guards), dann gibt es einen Fehler.
Vom Linker habe ich übrigens überhaupt nicht gesprochen. Es ging mir einfach nur darum, das ganze Problem anschaulich zu erklären. Aber sag mir doch bitte, wo genau ich was falsches gesagt habe. Und vor allem: Wenn das, was ich sagte, Unsinn ist (kann ja durchaus sein), wo liegt denn Deiner Meinung nach der Fehler in seinem Programm.
-
@NES:
Schrieb CStoll doch schon. Das Problem was Du geschildert hast (zwei OBJs werden zu einer EXE, in beiden OBJs ist die Konstante definiert) wird durch Deine Lösung nicht gelöst. Include-Guards verhindern _nicht_ das Sichtbarsein von zweimal der Konstante in zwei Objekten.
-
was dann zu den zwei OBJ-Dateien wird, welche wiederum zu einer Exe-Datei verarbeitet werden.
Genau dieser Arbeitsschritt passiert nicht im Compiler (der verarbeitet jede CPP-Datei zu einer OBJ-Datei), sondern im Linker. Und den Linker stört es nicht, wenn mehrere OBJ-Dateien die selbe Konstante definiert haben.
wo liegt denn Deiner Meinung nach der Fehler in seinem Programm.
Die Funktionsdefinitionen sollen nicht in den Header, sondern in die zugehörige CPP-Datei - dann werden sie vom Compiler auch nur in eine einzige OBJ-Datei gepackt. Alternativ können sie als static oder inline deklariert werden, dann werden sie vom Linker nicht mehr angefasst (static) bzw. vom Compiler direkt in die übergeordnete Funktion eingebaut (inline).
(und gegen Beschwerden des Linkers helfen auch keine Include-Guards)
-
Genau dieser Arbeitsschritt passiert nicht im Compiler (der verarbeitet jede CPP-Datei zu einer OBJ-Datei), sondern im Linker.
Wer hier was wie umwandelt, habe ich auch gar nicht explizit erwähnt. Ich sagte zwar: "dann macht der Compiler daraus etwas, was Du Dir so vorstellen kannst: [Hier folgte Quellcode]", jedoch war die Aussage "was dann zu den zwei OBJ-Dateien wird, welche wiederum zu einer Exe-Datei verarbeitet werden" ganz allgemein gehalten. Ich sagte ja nicht "Dann wandelt der Compiler die OBJ-Dateien in eine Exe-Datei um." Das heißt, wann hier der Linker und wann der Compiler etwas tut, wurde zumindest im letzten Teilsatz gar nicht mehr gesagt.
Die Funktionsdefinitionen sollen nicht in den Header, sondern in die zugehörige CPP-Datei - dann werden sie vom Compiler auch nur in eine einzige OBJ-Datei gepackt.
Ja, ich sehe jetzt auch, daß das daran lag.