Ich habe hier ein kleines "Problem" - ich habe verschiedene Dateien
welche auf die selben Header zugreifen. Um mir das ganze ein bisschen zu
vereinfachen wollte ich nun dies alles einer einzelnen Header
unterbringen, quasi so:
Die Hauptheader welche die ganzen Headerdateien includiert:
main.h
1
#ifndef MAIN_H_
2
#define MAIN_H_
3
4
#include"Funktionen.h"
5
//...
6
7
8
#endif
- Funktionen.h
1
#ifndef FUNKTIONEN_H_
2
#define FUNKTIONEN_H_
3
4
voidFunktion(void);
5
6
#endif
Und wenn ich nun in meinen anderen Dateien die Datei main.h einbinde,
schimpft mich der Compiler / Linker an das die Funktion "Funktion"
mehrfach deklariert ist. Kann ich das irgendwie umgehen?
- Programm1.c / Programm2.c / Sonstwas.c
DraconiX schrieb:> schimpft mich der Compiler / Linker an das die Funktion "Funktion"> mehrfach deklariert ist.
Wer meckert denn nun?
Bitte die genaue Fehlermeldung (per Copy&Paste).
DraconiX schrieb:> Ich habe hier ein kleines "Problem" - ich habe verschiedene Dateien> welche auf die selben Header zugreifen. Um mir das ganze ein bisschen zu> vereinfachen wollte ich nun dies alles einer einzelnen Header> unterbringen, quasi so:
Solche "Generalideen" sind im allgemeinen nicht zweckmäßig. Aber
zugegeben: Die hatten wir alle mal. :-)
> Und wenn ich nun in meinen anderen Dateien die Datei main.h einbinde,> schimpft mich der Compiler / Linker an das die Funktion "Funktion"> mehrfach deklariert ist. Kann ich das irgendwie umgehen?
Die Idee des "Umgehens" ist im allgemeinen auch nicht zweckmäßig. Aber
auch die hatten wir alle mal.
Wie lautet die Fehlermeldung genau? Von wem kommt sie genau? Vom Linker
oder vom Compiler?
Am besten erzeugst Du ein minimales Projekt, dass für uns compilierbar
ist und den Fehler aufweist. Bitte konkrete Angaben zu
Entwicklungsumgebung machen.
DraconiX schrieb:> Und wenn ich nun in meinen anderen Dateien die Datei main.h einbinde,> schimpft mich der Compiler / Linker an das die Funktion "Funktion"> mehrfach deklariert ist. Kann ich das irgendwie umgehen?
Ja. Und zwar, indem du das Ganze nicht derart falsch angehst wie du es
gepostet hast, sondern es richtig machst.
Also:
Eine Header-Datei hat den Zweck, daß andere Dateien Dinge sehen und
verwenden können, die in der eigentlichen Quell-Datei vorhanden sind.
Also gehört keine einzige Funktion und keine einzige Variable in eine
Headerdatei! Was da hineingehört, ist eine Referenz durch das Verwenden
von "extern". Lediglich Typdefinitionen gehören dann (und nur dann!) in
die Headerdatei, wenn sie von außen tatsächlich benötigt werden. ALLES
ANDERE GEHÖRT NICHT HINEIN.
Beispiel:
in karlheinz.c steht
long Emil;
static int Meingeheimnis; // wird anderen nicht zur Kenntnis gegeben
void HauDenLukas(int Otto)
{ Emil = Otto;
}
und in der zugehörigen Headerdatei karlheinz.h steht
#ifndef KARLHEINZINCLUDED
#define KARLHEINZINCLUDED
extern long Emil;
extern void HauDenLukas(int Otto);
#endif
So, das war's. Dieses karlheinz.h kann man überall inkludieren, auch
mehrfach, das stört nicht. Alle Programme, die dies inkludieren, kennen
damit auch Emil und HauDenLukas und können selbige benutzen, obwohl
beides tatsächlich in karlheinz.c steht. Hingegen Meingeheimnis steht
nicht im Header und kann deshalb auch nicht woanders eingesehen werden.
Das erreicht man durch das falsch verstehbare "static" (wer kommt schon
von allein drauf, daß das sowas wie "private" bedeuten soll...)
Ist dir das jetzt klar geworden?
W.S.
W.S. schrieb:> Also gehört keine einzige Funktion und keine einzige Variable in eine> Headerdatei! Was da hineingehört, ist eine Referenz durch das Verwenden> von "extern".
Das extern ist bei Funktionen nicht nötig und auch nicht üblich.
Das vom TE gepostete Beispiel ist völlig korrekt und stellt auch nur
eine "Referenz" (korrekter: Deklaration) dar:
DraconiX schrieb:> - Funktionen.h> #ifndef FUNKTIONEN_H_> #define FUNKTIONEN_H_>> void Funktion(void);>> #endif
Rolf M. schrieb:> Das extern ist bei Funktionen nicht nötig und auch nicht üblich.
Was ist denn das für ein Argument in einem formalen Konstrukt wie einer
Programmiersprache, wenn man denn das Kultobjekt "C" mit all ihren
Konventionen und obstrusen Freiheiten als solche bezeichnen möchte.
Da war Niklaus Wirth schon deutlich weiter
C-Kritiker schrieb:> Rolf M. schrieb:>> Das extern ist bei Funktionen nicht nötig und auch nicht üblich.>> Was ist denn das für ein Argument
Du hältst es nicht für sinnvoll, sich an Konventionen zu halten?
Wo genau bitte ist Euer Problem? Was W.S. schreibt ist, recht
weitschweifend formuliert aber doch, genau der Weg der seit Jahrzehnten
für C++ Header den Standard darstellt.
Aber ohne die Diskussion um des Kaisers Bart geht's in dem Forum wohl
nicht.
Rufus Τ. F. schrieb:> Das Schlüsselwort extern vor Funktionsprototypen?>> Ach.
Ja, gut so. Nix "ach".
mag ja sein, daß du seit Jahrzehnten schludrig programmiert hast, weil
das in C eben geht. Aber das dedizierte extern auch vor
Funktionsprototypen hat seinen Sinn, es schafft nämlich Klarheit. Auch
für dich, wenn du mal auf ne Quelle schaust, die du nicht selber
geschrieben hast. Aber ich werfe dir das nicht vor, schließlich ist es
für C-Programmierer ja ein richtiger Seelenschmerz, irgend etwas
ausführlich und dediziert hinzuschreiben. Am liebsten würden sie die
Welt in ein einziges nonprintable-Zeichen zusammenfassen.
W.S.
W.S. schrieb:> schließlich ist es> für C-Programmierer ja ein richtiger Seelenschmerz, irgend etwas> ausführlich und dediziert hinzuschreiben. Am liebsten würden sie die> Welt in ein einziges nonprintable-Zeichen zusammenfassen.
ich glaube, da verwechselst du was mit Assembler Programmierer
W.S. schrieb:> mag ja sein, daß du seit Jahrzehnten schludrig programmiert hast, weil> das in C eben geht.
Daran ist rein gar nichts "schludrig".
> Aber das dedizierte extern auch vor Funktionsprototypen hat seinen Sinn,> es schafft nämlich Klarheit.
Ich hab bisher außer bei dir noch nie gesehen, dass jemand das so macht.
Und ich habe noch nie erlebt, dass deshalb irgendwem etwas unklar ist.
Wenn überhaupt, würden sich bei deiner Schreibweise einige wundern und
sich fragen, was das bedeutet, weil sie es vorher noch nie gesehen
haben.
Du schreibst dann wohl auch bei jeder nicht-statischen lokalen Variable
auch das dafür vorgesehene "auto" davor und statt "short s;" lieber
"short int s;", weil es "schludrig" wäre, das wegzulassen?
Also das eine Funktion Extern definiert wird, ist mir auch schon des
öfteren über den Weg gelaufen, selbst von CubeMX erzeugter Code
verwendet dies. Der Sinn dahinter ist mir eigentlich auch relativ
schnell klar geworden wenn man die Datei und Verlinkungs-Hierarchie
betrachtet.
Genauso wie fast alle Compiler "signed" als implizit annehmen wenn man's
nicht über "unsigned" explizit anders einstellt.
Bis, ja bis irgendwann irgendein Compilerhersteller auf die glorreiche
Idee kommt und meint, dass der Standard ja schon viel zu lange falsch
ist und es eigentlich andersrum gehört. Ja, MS, ich schau in Deine
Richtung! Bisher hat noch JEDE Visual Studio Version irgendetwas an das
man sich endlich gewöhnt hatte wieder über den Haufen werfen müssen.
Und dann kompilieren "sonderbarerweise" viele Programme nicht mehr oder
stürzen mit sehr seltsamen Fehlern in Grenzbereichen ab.
Schon deswegen ist es sicher kein Fehler, das was "eh implizit" vom
Compiler angenommen wird auch explizit so hinzuschreiben. Wer weiß was
die nächste Version des Compilers für "eh implizit" ansieht.
Heinz L. schrieb:> Bisher hat noch JEDE Visual Studio Version irgendetwas an das man sich> endlich gewöhnt hatte wieder über den Haufen werfen müssen.
Tatsächlich? Und Du beziehst Dich auf C bzw. C++? Das würde mich
wundern, denn insbesondere bei C++ ist MS seit Jahren ausgesprochen
standardkonform.
Was magst Du meinen?
Mit so einem Super-H-File wird bedingtes Compilieren fast unmöglich. Bei
einer Änderung in einem beliebigen .h File muss immer das gesamte
Projekt neu übersetzt werden. Sehr praktisch am Anfang, aber mit
zunehmender Projektgröße immer nerviger. Dummerweise ist es dann fast
unmöglich, das Konstrukt wieder loszuwerden.
Gruß, Stefan
Rolf M. schrieb:> Du schreibst dann wohl auch bei jeder nicht-statischen lokalen Variable> auch...
Ich halte solche Einwendungen bzw. Unterstellungen für dumme Sprüche -
um das mal klar zu sagen.
Das ist die gleiche Ebene wie die müßige Diskussion über Vorrang-Regeln.
Auch dort ist es allemal einfach besser, ne ordentliche Klammer zu
setzen.
Das schafft ne finale Klarheit, eben genau wie das 'extern' vor externen
Funktionen.
Sollte doch einleuchtend sein!
Gute Lesbarkeit und damit auch gute Wartbarkeit usw. erreicht man nicht
durch das Hinweisen darauf, daß man ja dies und das auch weglassen kann,
weil der Compiler in solchen Fällen eine Default-Regelung hernimmt.
Ich sehe C eher mit gewissem Abstand. Da fallen einem die Defizite von C
auf, für die ein reiner C-Programmierer schon längst betriebsblind
geworden ist. Vielleicht ist es das, was dir so unbekannt vorkommt und
deswegen deine Verwunderung auslöst.
W.S.
W.S. schrieb:> Das schafft ne finale Klarheit, eben genau wie das 'extern' vor externen> Funktionen.
Das heißt du packst das extern an alle Funktions Deklarationen in
Headern? Da das aber an allen Funktionen dran steht ist es etwas
witzlos, weil es nichts unterscheidet - kein Informationsgewinn. Man
kann sich das extern ja hin denken, wenn es eine .h Datei ist.
Außerdem ist die Funktion ja nicht mehr extern wenn du den Header von
der .c Datei aus inkludierst, welche die Funktion auch definiert. Machst
du dann eine Konstruktion mit #ifdef um das extern dann abzuschalten? Ob
das besser lesbar ist?
Dr. Sommer schrieb:> Das heißt..
.. daß es eben ein Unterschied ist, ob eine Vorwärts-Definition in der
gleichen Quelle aufgelöst wird oder in einer anderen Quelle.
Das heißt aber auch, daß das System der Modularisierung bei C einfach
nur stümperhaft und schlecht gelöst ist. Pascal macht das um Längen
besser. Aber auch diese Diskussion ist müßig. Wenn's dich wirklich
interessieren sollte, dan guck einfach in das, was ich gelegentlich
poste. Dort siehst du, wonach du fragst.
So. Die hier aufgekommene Diskussion über 'extern" kann man schlichtweg
in die Frage zusammenfassen:
Soll man Default-Annahmen in C ausnutzen beim Programmieren oder nicht?
Hier kann nun ein jeder sein Kreuzchen bei
[ ]ja oder [ ]nein
machen.
Meine Antwort dazu ist ein klares nein. Man sollte Default-Regelungen
als eine Art Sicherheits-Schicht auffassen, also etwa wie ein Netz unter
dem Trapez, auf dem man grad herumturnt. Folglich soll man nur mit
Vorsicht sich drauf stützen und beim Programmieren mit Augenmaß
arbeiten, denn es geht ja nicht nur um das, was der Compiler darunter
versteht, sondern auch darum, was ein menschlicher Leser da sieht und
versteht. Also sollte man Variablen vor dem ersten Lesen auch mal
beschrieben haben, bei Ausdrücken mit Klammern arbeiten wo es Sinn
macht, bei externen Variablen, echten Konstanten und Funktionen nicht
auf das 'extern' verzichten, sich nicht drauf verlassen, daß ab
Programmstart aller RAM tatsächlich abgelöscht ist, und und und.. und so
weiter.
Es sei denn, man will das Verstehen seines eigenen Geschreibsels
behindern. Soll ja genug Leute geben, denen Obfuskation am Herzen liegt.
So, das war's.
W.S.
W.S. schrieb:> So. Die hier aufgekommene Diskussion über 'extern" kann man schlichtweg> in die Frage zusammenfassen:>> Soll man Default-Annahmen in C ausnutzen beim Programmieren oder nicht?>> Hier kann nun ein jeder sein Kreuzchen bei>> [ ]ja oder [ ]nein>> machen.> Meine Antwort dazu ist ein klares nein.
Siehst du, und genau deshalb habe ich gefragt, ob du dann bei lokalen
Variablen "auto" und bei "short int" das "int" auch hinschreibst, was du
dann als "Unterstellung" und "dumme Sprüche" bezeichnet hast. Wenn du
das weglässt, sind das aber auch "Default-Annahmen", ganz genau wie bei
"extern". Beantwortet hast du die Frage, ob du auch da konsequent deiner
eigenen Regel folgst, aber nicht.
Für mich geht es an der Stelle wie oben schon geschrieben auch nicht um
die von dir genannte Frage, sondern um diese:
Soll man
a) Sich lieber an den allgemein üblichen Stil der Programmiersprache
halten, in der man programmiert oder
b) lieber sein eigenes Ding machen?
Und da ist meine Antwort a).
> Folglich soll man nur mit Vorsicht sich drauf stützen und beim> Programmieren mit Augenmaß arbeiten, denn es geht ja nicht nur um das,> was der Compiler darunter versteht, sondern auch darum, was ein> menschlicher Leser da sieht und versteht.
Dazu muss man nicht alles, was man theoretisch hinschreiben könnte, auch
zwingend hinschreiben. "Augenmaß" ist da genau das richtige Stichwort:
"auto" schreibe ich nicht vor jede nicht-statische lokale Variable, weil
es keinen Informationsgewinn bietet und praktisch nur unnötiges Rauschen
ist - wie "extern" bei Funktionsdeklarationen.
> Es sei denn, man will das Verstehen seines eigenen Geschreibsels> behindern.
Gut, sofern andere deinen Code nicht lesen müssen, sondern nur du
selbst, kannst du natürlich auf die allgemeinen Gepflogenheiten
verzichten und einen Stil nutzen, der speziell auf dich selbst
abgestimmt ist.
Das Beispiel mit auto ist ganz übel, weil es ein Relikt aus "B" ist ...
Weg damit. In block-scope ist das default.
Außerdem: falls man den Blick auf C++ erweitern möge: dort ist das
abgeschafft und an anderer(!) Stelle als Typinferenz wieder eingeführt
worden.
Aber das hilft ja dem TO nicht.
Vielleicht sollte der seine old-school include-guards auf
#pragma once
umstellen (hat ja einiger Vorteile).