ubuntuusers.de

C++ Headerdateien *.h

Status: Gelöst | Ubuntu-Version: Nicht spezifiziert
Antworten |

root_Luk-As

Avatar von root_Luk-As

Anmeldungsdatum:
14. März 2010

Beiträge: 373

Wohnort: Berlin

Hallo, ich habe eine Frage, was kann man in eigene #include "EigenerHeader.h" schreiben? Ich habe gelesen, dass man dort nur Funktionsprototypen, also ohne Körper reinschreiben darf. Aber wo ist der Körper der Funktion dann?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
//Prototyp einer Funktion
int IeineFunktion(double, int);
int main( ... )
{
IeineFunktion(1,3);
}
//Und jetzt der Körper
int IeineFunktion(double argument1, int Argument2);
{
//etwas tun
}

Aber wenn ich #include<I-eine STL-Bibliothek Header.h> einbinde, dann muss ich den Funktionskörper nicht schreiben. Kann ich irgendwie Prototypen & Funktionen in eine HEADER-Datei packen, damit ich den Körper nicht immer schreiben muss?

Gruß, Lukas

Lunar

Anmeldungsdatum:
17. März 2006

Beiträge: 5792

Der Funktionskörper befindet sich in der entsprechenden "*.cpp"-Datei. Für Funktionen, die Du selbst schreibst, ist also eine Header-Datei mit der Deklaration und eine Quelldatei mit der Implementierung erforderlich. Die Quelldatei musst Du an den Compiler übergeben.

Bei "fertigen" Bibliotheken ist die Implementierung der Funktion als Binärcode in der Bibliothek enthalten. Dem Entwickler steht nur die Deklaration zur Verfügung. Die Deklaration auf die entsprechende Funktion in der Bibliothek abzubilden, ist dann Sache des Linkers im dritten Übersetzungsschritt (nach Präprozessor und Compiler).

tischbein

Avatar von tischbein

Anmeldungsdatum:
21. Juli 2008

Beiträge: 404

root Luk-As schrieb:

Hallo, ich habe eine Frage, was kann man in eigene #include "EigenerHeader.h" schreiben? Ich habe gelesen, dass man dort nur Funktionsprototypen, also ohne Körper reinschreiben darf.

Sowas hab ich noch nie gelesen/gehört. Wenn das wirklich so sein soll, halt ich das für ausgesprochen diskussionswürdig. 😉

Aber wo ist der Körper der Funktion dann?

Theoretisch betrachtet, kannst du den Körper der Funktionen auch in die Header-dateien packen.
Praktisch aber, kommt es auf die Applikation an, die du schreiben willst. Applikationen die eine API bereitstellen (wollen), sollten nur ihre Prototypen in eine eigene header-datei packen.

Lunar

Anmeldungsdatum:
17. März 2006

Beiträge: 5792

@tischbein: Wenn Header-Dateien Implementierungen enthalten, fügt der Präprozessor diese Implementierung in jede Datei ein, die den Header einbindet. Sind die Deklarationen dann nicht static, führt das beim Linken zu Fehlern. In C++ gilt zudem, dass eine Implementierung, die innerhalb der Deklaration einer Klasse steht, vom Compiler automatisch als inline betrachtet wird, und das ist nur selten das, was man will.

Es gibt keine vom Compiler erzwungene Regel, die Implementierung auszulagern, aber in der Praxis „darf“ man es trotzdem nicht ☺

tischbein

Avatar von tischbein

Anmeldungsdatum:
21. Juli 2008

Beiträge: 404

Lunar schrieb:

@tischbein: Wenn Header-Dateien Implementierungen enthalten, fügt der Präprozessor diese Implementierung in jede Datei ein, die den Header einbindet. Sind die Deklarationen dann nicht static, führt das beim Linken zu Fehlern.

Dafür gibt es

1
2
3
4
5
6
7
8
#ifndef MYHEADER
#define MYHEADER
void blubb()
{
    mach_irgendwas();
}

#endif

Das verhindert ganz einfach, dass Funktionen jedesmal redefiniert werden.
Findet sich in jedem besseren C++ Tutorial und Buch.

In C++ gilt zudem, dass eine Implementierung, die innerhalb der Deklaration einer Klasse steht, vom Compiler automatisch als inline betrachtet wird, und das ist nur selten das, was man will.

Das wusste ich nicht, auch wenn es mich wundern würde. Gibts da mehr Informationen zu?

Es gibt keine vom Compiler erzwungene Regel, die Implementierung auszulagern, aber in der Praxis „darf“ man es trotzdem nicht ☺

Boost tut es seit geraumer zeit, und ziemlich erfolgreich.

root_Luk-As

(Themenstarter)
Avatar von root_Luk-As

Anmeldungsdatum:
14. März 2010

Beiträge: 373

Wohnort: Berlin

das heißt, ich muss meinen Funktionskörper in den header packen? 😢 ihr seid ja ziemlich unterschiedlicher Meinung. Ich habe 3 C++ Bücher und im I-net geforscht, aber nirgendwo stand da was. Also, welche der Beiden Versionen würde beim Kompilieren nicht zum Fehler führen? (theoretisch gesehen) Version 1

1
2
//Inhalt der Headerdatei 1
void ShhreibCpp (void);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
//Quelltext
#include <blabla>
#include "H1.h"
main()
{
ShhreibCpp()
void ShhreibCpp (void){
 cout << "CPP";}
//getch: warten, bis Tastendruck; wie auf Windows system("pause");
getch;}

oder

Version 2

1
2
3
4
//Inhalt der Headerdatei 2
void ShhreibCpp (void);{
printf("CPP");
//pintf ist c++ bekannt (auch scanf) gute alte C-Befehle (-;, es ginge aber auch std::cout << "CPP"
1
2
3
4
5
6
7
8
//Quelltext
#include <blabla>
#include "H2.h"
main()
{
ShhreibCpp()
//getch: warten, bis Tastendruck; wie auf Windows system("pause");
getch;}

Vielen Dank für die Antworten bisher

mfg, Lukas

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4694

Wohnort: Berlin

@tischbein: Ich sehe nicht wie die Präprozessoranweisungen das Problem lösen sollen!? Ich denke Du hast das Problem nicht einmal verstanden. Wenn Du diesen Header bei zwei unabhängigen Compileraufrufen in zwei Modulen einbindest und die resultierenden Object-Dateien zu einem Binary linkst, hast Du zwei Module die jeweils eine Kopie der blubb()-Funktion haben. Und das geht halt nicht, weil der Linker dann nicht weiss welche er nehmen soll. Beispiel:

test.h:

1
2
3
4
5
6
7
8
#ifndef MYHEADER
#define MYHEADER
int blubb()
{
    return 42;
}

#endif

test_a.cpp:

1
2
3
4
5
6
#include "test.h"

int main()
{
    return 0;
}

test_b.cpp:

1
#include "test.h"

Und jetzt versuchen wir das mal zu kompilieren:

bj@s8n:~$ g++ -c test_a.cpp
bj@s8n:~$ g++ -c test_b.cpp
bj@s8n:~$ g++ test_a.o test_b.o
test_b.o: In function `blubb()':
test_b.cpp:(.text+0x0): multiple definition of `blubb()'
test_a.o:test_a.cpp:(.text+0x0): first defined here
collect2: ld returned 1 exit status 

Du tönst hier rum was angeblich in jedem besseren Buch oder Tutorial steht, hast aber anscheinend selbst wenig Ahnung von der Materie. Denn das Methodendefinitionen innerhalb von Klassendeklarationen implizit inline sind, sollte eigentlich auch in jedem besseren Buch oder Tutorial stehen, denn das ist Bestandteil der Sprachdefinition und nicht ganz unwichtig.

tischbein

Avatar von tischbein

Anmeldungsdatum:
21. Juli 2008

Beiträge: 404

root Luk-As schrieb:

das heißt, ich muss meinen Funktionskörper in den header packen? 😢

Du musst nicht, wie du es tust ist dir überlassen. 😉

@Marc 'BlackJack' Rintsch:
Ich habs tatsächlich missverstanden, danke. ☺
Das beschriebene Problem habe ich allerdings noch nie gehabt.

YEPHENAS

Anmeldungsdatum:
8. Juni 2009

Beiträge: 352

root Luk-As schrieb:

das heißt, ich muss meinen Funktionskörper in den header packen? 😢 ihr seid ja ziemlich unterschiedlicher Meinung. Ich habe 3 C++ Bücher und im I-net geforscht, aber nirgendwo stand da was. Also, welche der Beiden Versionen würde beim Kompilieren nicht zum Fehler führen? (theoretisch gesehen)

Also ehrlich gesagt würden beide zu Fehlern beim Kompilieren führen. Sinnvoll ist: Deklarationen in den Header, Implementierungen in die .cpp Datei. Daher ist deine 1. Version tendenziell eher auf dem richtigen Weg.

Ein paar allgemeine kleine Tipps für dich:

- keine Funktionen innerhalb von Funktionen definieren, stattdessen außerhalb

- Funktionsaufrufe ohne Parameter müssen auch Klammern haben, also getch() statt getch

- Lesbarkeit: immer schön konsequent einrücken mit Leerzeichen oder Tabs. Geschweifte Klammer zu macht man in der Regel in eine eigene Zeile

- Rechtschreibung auch im Quelltext beachten (Schreib statt Shhreib), am besten Englisch statt Deutsch

- Die main() Funktion sollte int als Rückgabetyp haben und einen Exitcode per return zurückliefern (0 für kein Fehler, größer 0 für Fehler aufgetreten)

- Deine Headerdateien wie weiter oben schon beschrieben mit Präprozessoranweisungen wie

#ifndef MYHEADER
#define MYHEADER
// ...
#endif

jeweils vor Mehrfachinkludierungen schützen.

- Möglicherweise eine leichtere Programmiersprache als C++ für den Einstieg erlernen

Lunar

Anmeldungsdatum:
17. März 2006

Beiträge: 5792

@tischbein: Boost tut das nur für bestimmte Bibliotheken, die ausschließlich aus Templates bestehen. Bei Templates ist es zwingend erforderlich, dass die Implementierung im Header enthalten ist, sofern keine expliziten Spezialisierungen vorliegen. Und das steht auch in jedem besseren Buch oder Tutorial ...

Boost-Bibliotheken, die auch normale Typen enthalten, sind dagegen ganz normale Bibliotheken, die entsprechend gelinkt werden müssen, weil die Implementierung eben nicht im Header enthalten ist. Beispiele sind filesystem, program_options oder datetime.

Den Rest hat BlackJack ja schon gesagt …

root_Luk-As

(Themenstarter)
Avatar von root_Luk-As

Anmeldungsdatum:
14. März 2010

Beiträge: 373

Wohnort: Berlin

YEPHENAS schrieb:

Ein paar allgemeine kleine Tipps für dich:

- keine Funktionen innerhalb von Funktionen definieren, stattdessen außerhalb

also auch nicht in der main() funktion?

- Funktionsaufrufe ohne Parameter müssen auch Klammern haben, also getch() statt getch

seit wann müsssen funktionsaufrufe Klammern haben?Habe ich eine seltsame Umgebung????!!

- Lesbarkeit: immer schön konsequent einrücken mit Leerzeichen oder Tabs. Geschweifte Klammer zu macht man in der Regel in eine eigene Zeile

ist auch in jedem Buch so ☺

- Rechtschreibung auch im Quelltext beachten (Schreib statt Shhreib), am besten Englisch statt Deutsch

ok

- Die main() Funktion sollte int als Rückgabetyp haben und einen Exitcode per return zurückliefern (0 für kein Fehler, größer 0 für Fehler aufgetreten)

ich habe ein Buch mit spezieller Entwicklungsumgebung, die spzielle Argumentebenötigt, habe auf Windows ganz passabel programmiert, aber auf Linux ist alles andedrs 😢 Falls es dich interessiert:

main(int nNumberofArgs, char* pszArgs[])

bei mir ist return 0; UND GETCH() hatte ich auch nur woanders gefunden, auf meiner Umgebung (für WinDoof) heißts: system("pause"); (sind Stapelverarbeitungs/DOS-Befehle, hatte da schon EWrdfahrung –> keine Probleme –> coole Sachen) hatte bloß keinen Bock das noch zu posten, ist ja egal. Soll das beste sein. Klappt ja viell. auch auf anderen Umgebungen. Kann man ja mal probieren

- Deine Headerdateien wie weiter oben schon beschrieben mit Präprozessoranweisungen wie

#ifndef MYHEADER
#define MYHEADER
// ...
#endif

jeweils vor Mehrfachinkludierungen schützen.

das heißt?

kann man auch includes in includes packen?

- Möglicherweise eine leichtere Programmiersprache als C++ für den Einstieg erlernen

ich hab viele Programmierer in meiner Umgebung. Einer schrie JAVA, einer C++, ...

mfg, Lukas FROHE OSTERN !!!

Vain

Avatar von Vain

Anmeldungsdatum:
12. April 2008

Beiträge: 2510

root Luk-As schrieb:

seit wann müsssen funktionsaufrufe Klammern haben?Habe ich eine seltsame Umgebung????!!

Mal mit aktivierten Warnungen kompiliert?

$ cat bla.cpp
#include <iostream>
using namespace std;

void nix()
{
        cout << "Hallo" << endl;
}

int main(int argc, char **argv)
{
        nix;
        return 0;
}
$ g++ -Wall -Wextra -o bla bla.cpp
bla.cpp: In function ‘int main(int, char**)’:
bla.cpp:11: warning: statement is a reference, not call, to function ‘nix’
bla.cpp:11: warning: statement has no effect
bla.cpp: At global scope:
bla.cpp:9: warning: unused parameter ‘argc’
bla.cpp:9: warning: unused parameter ‘argv’
$ ./bla
$

root_Luk-As

(Themenstarter)
Avatar von root_Luk-As

Anmeldungsdatum:
14. März 2010

Beiträge: 373

Wohnort: Berlin

- Möglicherweise eine leichtere Programmiersprache als C++ für den Einstieg erlernen

ich hab viele Programmierer in meiner Umgebung. Einer schrie JAVA, einer C++, ...

hab auch schon gehab: TurboPascal, QBasic, vbs, Batch(Stapelverarbeitung auf Windows) ...Vain schrieb:

root Luk-As schrieb:

seit wann müsssen funktionsaufrufe Klammern haben?Habe ich eine seltsame Umgebung????!!

Mal mit aktivierten Warnungen kompiliert?

ne, noch nicht...

aber sry, hatte doch immer Klammern geschreiben, hatte das mit "" verwechselt (-;, hätte mich nämlich gewundert.

ka wies geht =) viell. kanns die Umgrbung (Dev-Cpp, Bloodshet) nicht

frohe ostern

welche <umgebung würdet ihr für linux empfehlen? ich hab netbeans...

YEPHENAS

Anmeldungsdatum:
8. Juni 2009

Beiträge: 352

root Luk-As schrieb:

YEPHENAS schrieb:

Ein paar allgemeine kleine Tipps für dich:

- keine Funktionen innerhalb von Funktionen definieren, stattdessen außerhalb

also auch nicht in der main() funktion?

Genau, auch nicht in der main()-Funktion.

- Funktionsaufrufe ohne Parameter müssen auch Klammern haben, also getch() statt getch

seit wann müsssen funktionsaufrufe Klammern haben?Habe ich eine seltsame Umgebung????!!

Bei C oder C++ schon immer. Aber du hast es ja schon gemerkt.

- Die main() Funktion sollte int als Rückgabetyp haben und einen Exitcode per return zurückliefern (0 für kein Fehler, größer 0 für Fehler aufgetreten)

ich habe ein Buch mit spezieller Entwicklungsumgebung, die spzielle Argumentebenötigt, habe auf Windows ganz passabel programmiert, aber auf Linux ist alles andedrs 😢 Falls es dich interessiert:

main(int nNumberofArgs, char* pszArgs[])

FAQ: Can I write "void main()"?

Die beiden Parameter sind schon richtig so, haben bei dir nur sehr ungewöhnliche Namen mit ungarischer Notation. Üblich ist folgende Signatur für main:

int main(int argc, char* argv[])

Ein fehlender Rückgabetyp ist nicht standardgemäß, auch wenn das manche Compiler erlauben.

UND GETCH() hatte ich auch nur woanders gefunden, auf meiner Umgebung (für WinDoof) heißts: system("pause"); (sind Stapelverarbeitungs/DOS-Befehle, hatte da schon EWrdfahrung –> keine Probleme –> coole Sachen) hatte bloß keinen Bock das noch zu posten, ist ja egal. Soll das beste sein. Klappt ja viell. auch auf anderen Umgebungen. Kann man ja mal probieren

Bei dem Absatz hab ich nicht verstanden, was du sagen willst.

jeweils vor Mehrfachinkludierungen schützen.

das heißt?

kann man auch includes in includes packen?

Ja.

root_Luk-As

(Themenstarter)
Avatar von root_Luk-As

Anmeldungsdatum:
14. März 2010

Beiträge: 373

Wohnort: Berlin

cool, danke für die Antworten!YEPHENAS schrieb:

ich habe ein Buch mit spezieller Entwicklungsumgebung, die spzielle Argumentebenötigt, habe auf Windows ganz passabel programmiert, aber auf Linux ist alles andedrs 😢 Falls es dich interessiert:

main(int nNumberofArgs, char* pszArgs[])

FAQ: Can I write "void main()"?

Die beiden Parameter sind schon richtig so, haben bei dir nur sehr ungewöhnliche Namen mit ungarischer Notation. Üblich ist folgende Signatur für main:

int main(int argc, char* argv[])

aha

UND GETCH() hatte ich auch nur woanders gefunden, auf meiner Umgebung (für WinDoof) heißts: system("pause"); (sind Stapelverarbeitungs/DOS-Befehle, hatte da schon EWrdfahrung –> keine Probleme –> coole Sachen) hatte bloß keinen Bock das noch zu posten, ist ja egal. Soll das beste sein. Klappt ja viell. auch auf anderen Umgebungen. Kann man ja mal probieren

Bei dem Absatz hab ich nicht verstanden, was du sagen willst.

damit will ich sagen, dass der Befehl, der benötigt wird, damit das Programm nicht sofort schließt, getch(); heißt (glaube ich zumindest, in meiner Umgrbung ist das anders), aber auf meiner umgebung nutzt er den Stapelverarbeitungs(Batch)-Befehl pause; Batch-Befehle sind DOS-und andere Befehle, d.h. mehrere Befehle hintereinandergepackt und dann ausgeführt ... Da ich das schon konnte, hatte ich dort coole Möglichkeiten... Dass wollte ich einfach nur nicht schreiben, ist ja nicht ganz so wichtig...

mfg, Lukas

pass auf: ich b in die nächste woche weg, d.h., dass ich wahrscheinlich bis sonntag keine posts mehr lesen kann, erst danach kann ich wieder reagieren...

Antworten |