Hallo,
ich habe einen SourceCode (in c) bekommen, den ich mir angucken soll und
dann weiter bearbeiten soll.
Was mir auffällt, das alle Funktionen und Variablen, die in anderen
dateien benutzt werden als extern deklariert sind. Die Header wird aber
in den jeweiligen c-files eingebunden.
file1.h
1
externuint8x;
2
externvoidfunction(void);
file1.c
1
voidfunction(void)
2
{
3
...
4
}
file2.c
1
#include file1.h
2
...
3
...
4
function();
5
...
Aber ich inkludiere doch file1.h. Damit sind die Funktionen ja
eigentlich vorhanden? Warum sind die Funktionen als extern deklariert?
markus schrieb:> Warum sind die Funktionen als extern deklariert?
Weil der Programmierer nicht wusste, dass "extern" bei Funktionen
komplett wirkungslos ist. Das kann man genau so gut weg lassen.
In file2.c verwendest du function(), die in file2.c nicht definiert ist.
Wäre function() nicht als extern deklariert. würde der Compiler den Code
für function() in der Datei file2.c suchen und dort nicht finden, weil
nicht vorhanden. file2.c wäre somit nicht compilierbar.
Die Deklaration als extern fügt hier, flapsig ausgedrückt, ein Symbol
ein, das später beim Zusammensetzen des gesamten Programms der Linker
referenzieren muss.
Somit kannst du bspw. eine Bibliothek für Displays schreiben, die für
die Ausgaben ein putpixel benötigen, die Funktion putpixel jedoch wird
in einer Datei definiert die den Treiber für das Display darstellt.
Somit können dann alle Funktionen für das Display wie zeichnen von
Linien, Rechtecken, Kreisen etc. in einer Datei stehen unabhängig davon,
welches Display verwendet werden soll. In deiner Treiberdatei steht dann
das putpixel. Arbeitest du mit mehreren unterschiedlichen Displays musst
du dann beim build nur den Treiber zu deinem Programm hinzulinken und
das putpixel wird von diesem verwendet (dein Programmgerüst oben zeigt
das ja schon sehr deutlich).
Zusammengefasst:
Die Deklaration als extern sorgt dafür, dass bei dir file2.c übersetzbar
ist, obwohl der Code für function() nicht bekannt ist.
Ralph S. schrieb:> In file2.c verwendest du function(), die in file2.c nicht> definiert ist.> Wäre function() nicht als extern deklariert. würde der Compiler den Code> für function() in der Datei file2.c suchen und dort nicht finden, weil> nicht vorhanden. file2.c wäre somit nicht compilierbar.
Falsch. Ohne "extern" macht er das genau gleich. Es gibt absolut
keinen Unterschied zwischen:
1
externvoidfunction(void);
und
1
voidfunction(void);
Er würde die Funktion nur dann nicht finden, wenn man diese Deklaration
ganz weglassen würde.
Bei Variablen ist das hingegen nicht so, da gibt es einen Unterschied.
1
externuint8_tx;
Besagt, dass später (oder in einer anderen Datei) die Definition
erfolgt;
Dr. Sommer schrieb:> Das kann man genau so gut weg lassen.
Wenn du mal irgendwann Langeweile haben solltest, kannst du gerne mal
ein C-Buch lesen ;-)
Das bringt was. Ehrlich!
Hugo schrieb:> Das bringt was. Ehrlich!
Das Echauffieren über die Fehler und unverständlichen Erklärungen ist
schlecht für meinen Blutdruck.
https://jameshfisher.com/2017/08/28/c-extern-function/
"Applied to a function declaration, the extern keyword in fact does
nothing: the declaration extern int incr(int) is exactly the same as int
incr(int). This is because all function declarations have an implicit
extern applied!"
Hugo schrieb:> Wenn du mal irgendwann Langeweile haben solltest, kannst du gerne mal> ein C-Buch lesen ;-)
weil alles Geschriebene in Bücher immer wahr ist?
ne das ist nur ein Irrglaube
ich schliesse mich Dr. Sommer an, bei Funktionen ist aktuell extern
unnötig.
OK,
vielleicht haben die das ja auch nur hingeschrieben, um es sofort
ersichtlich zu machen, dass diese Funktion noch in anderen files benutzt
wird? Aber andersrum, würde 'ich' Funktionen, die nur in einer file
benötigt werden in der c-file direkt als static deklarieren.
Aber wenn es sonst keinen unterschied macht, kann ich damit leben.
Wenigstens ist es einheitlich.
Danke euch schonmal für die Erläuterungen
markus schrieb:> vielleicht haben die das ja auch nur hingeschrieben, um es sofort> ersichtlich zu machen, dass diese Funktion noch in anderen files benutzt> wird?
Das ist bei Funktions-Deklarationen ohne "extern" in Header-Files
ebenfalls ersichtlich.
Die übliche Regel ist:
- Funktionen, die nur in 1 .c-Datei gebraucht werden, werden in dieser
.c-Datei mit "static" definiert, und ggf. am Anfang dieser Datei nochmal
deklariert
- Funktionen, die in mehr Dateien gebraucht werden, werden in der .c
Datei ohne "static" definiert und in der zugehörigen .h Datei
deklariert.
- Die .h Datei wird von der zugehörigen .c Datei inkludiert, um den
Compiler Unstimmigkeiten finden zu lassen.
- extern wird bei Funktionen nie benutzt
- Variablen, die nur in 1 .c-Datei gebraucht werden, werden am Anfang
dieser .c-Datei mit "static" definiert
- Variablen, die in mehr Dateien gebraucht werden, werden in der .c
Datei ohne "static" definiert und in der zugehörigen .h Datei mit
"extern" deklariert (hier die einzige Nutzung von extern!).
- Die .h Datei wird von der zugehörigen .c Datei inkludiert.
- Alle von Funktions- und Variablendeklarationen benötigten Typen
(typedef,struct,union) werden entweder davor in der .h Datei definiert,
oder in der .h Datei per #include eingebunden
- Alle .h Dateien haben Include-Guards (#ifndef-#define-#endif)
Dr. Sommer schrieb:> markus schrieb:>> vielleicht haben die das ja auch nur hingeschrieben, um es sofort>> ersichtlich zu machen, dass diese Funktion noch in anderen files benutzt>> wird?>> Das ist bei Funktions-Deklarationen ohne "extern" in Header-Files> ebenfalls ersichtlich.
Vor allem, da es um eine Deklaration im Header geht. Die macht man ja
gerade, damit die Funktion in anderen Files benutzt werden kann.
markus schrieb:> ich habe einen SourceCode (in c) bekommen, den ich mir angucken soll> und dann weiter bearbeiten soll.> extern void function(void);
Auch wenn das extern hier redundant ist, ich würd das einfach so lassen.
Das extern rauszukicken macht den Code weder effizienter noch besser
nachvollziehbar oder besser zu supporten.
Übrigens bedeutet das extern nicht notwendigerweise, dass function
external Linkage hat, insbesondere wenn eine static Deklaration /
Definition dem extern vorausgeht:
1
staticintf(void);
2
externintf(void);
ist gültiges C/C++. Aber das nur nebenbei, das ist eine "Feature" von
C/C++, und daran ändert auch ein Code-Review nix.
Für ein Review würde ich starten mit statischer Codeanalyse, d.h.
Warnungen aktivieren, auch solche die standardmäßig nicht an sind und
das Ergebnis bewerten. Und statische Analyse-Tools wie Lint verwenden.
Was Prototypen betrifft, z.B. -Wstrict-protoypes -Wmissing-prototypes
aktivieren falls GCC zum Einsatz kommt.
Es ist auch denkbar, dass die Deklaration
extern void function(void);
zunächst im Kopf von file1.c stand, dann aber festgestellt wurde, dass
Andere Module function() ebenfalls nutzen können sollten, und
konsequenterweise die Deklaration einfach mit Cut-und-Paste in einen
Headerfile ausgelagert wurde.
Die extern Deklaration im Quellfile kann als Explizitmachen, dass die
Funktion anderswo residiert, Sinn machen (sozusagen ein Gegenpol zu
static, obwohl natürlich static für den Compiler einen Unterschied
macht, extern aber nicht). Man kann auch argumentieren, dass es genau
dann Sinn macht, wenn man eben vermeiden will, dass Anderen Module die
Funktion pauschal sehen können (manchmal sind logisch zusammen gehörende
Funktionsgruppen über mehrere Quelldateien verteilt, um die Quellen
nicht unnötig aufzublähen, aber aus Modularisierungsgründen sollten die
zusammengehörenden Funktionsgruppen nicht global sichtbar sein).
Klar kann man dafür auch lokale Headerfiles verwenden. Oder noch Andere
Konstrukte. Oder die Entwickler feuern, die beim Cut-und-Paste vom
Quell- in den Headerfile nicht daran denken, das extern zu löschen. Oder
C ganz ablehnen, weil es so vieles durchgehen lässt. Oder oder oder.
Aber das ist müssig, weil vieles davon Stil- oder Konventionsfragen
sind, bei denen jede Variante begründet werden kann (so wie Kernighan
Ritchie oder Allman Klammerung. Manche mögen Kartoffeln lieber, manche
Nudeln).
Dr. Sommer schrieb:> - Variablen, die nur in 1 .c-Datei gebraucht werden, werden am Anfang> dieser .c-Datei mit "static" definiert
Das ist eine etwas unglückliche Formulierung. static verhindert, dass
Variablen in anderen Modulen sichtbar werden können, sie werden also vor
Zugriffen von außen geschützt.
Nich-static-Variablen können in beliebieg vielen Modulen benutzt werden,
also auch in nur einem.
Johann L. schrieb:> markus schrieb:>> ich habe einen SourceCode (in c) bekommen, den ich mir angucken soll>> und dann weiter bearbeiten soll.>>> extern void function(void);>> Auch wenn das extern hier redundant ist, ich würd das einfach so lassen.> Das extern rauszukicken macht den Code weder effizienter noch besser> nachvollziehbar oder besser zu supporten.
Es führt aber - wie man ja hier hervorragend sehen kann - zu
Irritationen, weil es sehr ungebräuchlich ist.
markus schrieb:> Aber ich inkludiere doch file1.h. Damit sind die Funktionen ja> eigentlich vorhanden? Warum sind die Funktionen als extern deklariert?
Eigentlich ist es alles ganz einfach:
Um eine Funktion korrekt aufrufen zu können, braucht man deren
Deklaration, wo der Compiler sehen kann, was diese Funktion an
Argumenten haben will und was sie denn so zurückliefert.
Ob nun die Funktion, die man aufrufen will, schlichtweg weiter oben im
Quelltext steht, oder ob mal bloß deren Kopfzeile als Prototyp weiter
oben im Quelltext steht, ist für's Aufrufen egal.
Bei Daten sieht das anders aus, da gibt es keine Prototypen. Also MUSS
man bei Daten, die eben nicht weiter oben im aktuellen Quelltext stehen,
ein 'extern' davorschreiben, damit der Compiler den Typ erkennen kann,
obwohl die eigentlichen Daten irgendwo in irgend einer anderen Datei
stehen - das kann auch die aktuelle Datei sein.
Nun kann man in einem Headerfile sich die Mühe machen, säuberlich zu
unterscheiden, ob irgendwas nun Funktion oder Daten ist, oder man
schreibt ganz einfach vor beides 'extern' davor - auch in Anbetracht
dessen, daß dieses bei Funktionen nicht unbedingt notwendig ist.
Aber es ist eine sinnvolle Vereinheitlichung, mit der man wenigstens
einmal eine Extrawurst in C beseitigt hat. Und es trägt zur Lesbarkeit
bei, weil menschliche Betrachter sofort sehen können, daß das als extern
bezeichnete Dingsbums eben nicht die Sache als solche ist, sondern eine
Referenz für etwas, das woanders steht.
W.S.
W.S. schrieb:> Und es trägt zur Lesbarkeit bei, weil menschliche Betrachter sofort> sehen können, daß das als extern bezeichnete Dingsbums eben nicht die> Sache als solche ist, sondern eine Referenz für etwas, das woanders> steht.
Das sieht man auch daran, dass auf das ) kein { sondern ein ; folgt. Ist
dann auch konsistent mit vielen anderen Sprachen, in denen es das extern
gar nicht gibt.
Wenn du das so konsequent verfolgst, müsstest du statt long auch signed
long int schreiben, denn long ist eigentlich nur ein Zusatz für den
darauf folgenden Typnamen. Wenn man den weglässt, wird implizit int
angenommen. Und signed ist auch eigentlich nicht nötig, wäre aber dann
konsequent, um es von unsigned zu unterscheiden.
Und wie ist es bei lokalen nicht-statischen Variablen? Da weiß ja
keiner, was das ist, wenn man nicht explizit auto davorschreibt, zur
Unterscheidung von static. Ein sehr verkanntes Schlüsselwort.
Dr. Sommer schrieb:> W.S. schrieb:>> Und es trägt zur Lesbarkeit bei, weil menschliche Betrachter sofort>> sehen können, daß das als extern bezeichnete Dingsbums eben nicht die>> Sache als solche ist, sondern eine Referenz für etwas, das woanders>> steht.>> Das sieht man auch daran, dass auf das ) kein { sondern ein ; folgt. Ist> dann auch konsistent mit vielen anderen Sprachen, in denen es das extern> gar nicht gibt.
für mich geht der Punkt an Dich Dr. Sommer, bzw an die
nicht-extern-hinschreiben Fraktion.
Solche Dinge liest man nicht denkend, sondern halb bewusst, halb
automatisch. Genau wie man viele Wörter nicht Buchstabe für Buchstabe
oder Silbe für Silbe zusammenstückelt, sondern am Stück als Muster
verdaut.
Die idiomatische Schreibweise ist es ganz klar, das "extern" bei
Funktionen nicht hinzuschreiben. Weicht man von der idiomatischen
Formulierung ab, staunt der Laie und der Fachmann wundert sich. Das
sollte man nicht ohne Not tun.
vlg
Timm
Rolf M. schrieb:> Wenn du das so konsequent verfolgst, müsstest du..
Ich? nein. Sondern 'man', sprich die C-Gremien. Was du schreibst, ist ja
in allen Punkten etwas, wo es in C im Argen liegt. Keine sauberen Typen,
kein Modulkonzept, überall Nebeneffekte, überall Defaults und
Extrawürste (sprich Workarounds)...
Weißt du, die Sprache C ist ganz genau so wie das Haus der Weasley's bei
Harry Potter:
Ursprünglich ein verlassener alter Schweinestall, dann hier was angebaut
und dort was aufgestockt und da nochmal was drangebaut - aber im Kern
noch immer der alte Schweinestall.
Das wirft auch ein Licht auf die Gilde der Programmierer, die sich darin
offensichtlich am allerwohlsten fühlen.
Naja, das Essen mit Messer und Gabel liegt ja auch nicht jedem, aus dem
Trog schmeckt's manchem wohl besser und ist auch nicht so kompliziert,
gelle - siehe McDonalds.
W.S.
Ich habe Programmiersprachen (und die Menschen, die sie verwenden)
früher auch ähnlich emotional gesehen, wobei mich meist eher gestört
hat, wenn in Sprachen Features, die eigentlich nützlich sind,
weggelassen werden, weil man den Programmierer für zu blöd hält, um sie
richtig zu verwenden. Das war für mich dann auch eine Aussage über die
Programmierer, die diese Sprache gerne verwenden - so ähnlich wie du es
gerade beschreibst.
Inzwischen versuche ich, die Emotionen rauszulassen und die Sprachen
einfach nur als Werkzeuge zu sehen, die ihre Stärken und Schwächen
haben. Und ich nutze einfach das, was für die Aufgabe geeignet ist und
womit ich am besten zurecht komme.
Rolf M. schrieb:> Inzwischen versuche ich, die Emotionen rauszulassen
Ja. Das ist ja auch vollkommen richtig so. Ich mache das ganz genau so.
Aber es kommt hier ja garnicht drauf an, dir oder mir die Sache mit dem
'extern' zu erklären, sondern ihm:
markus schrieb:> Was mir auffällt, das alle Funktionen und Variablen, die in anderen> dateien benutzt werden als extern deklariert sind. Die Header wird aber> in den jeweiligen c-files eingebunden.
Hier haben wir also jemanden, der noch logisch denken kann und das auch
tut - und dem fällt sowas natürlich auf, denn man nimmt ja zuvörderst
an, daß gerade hinter einer Programmiersprache Logik steckt.
Aber das ist hier eben nicht so, siehe Weasley's Haus. Die Logik fehlt
und die diversen "Ist hier so" gibt es nur deshalb, weil sie als
Workaround gegen andere Mißstände notwendig sind.
Muß man also im Jahre 2019 noch auswendig lernen, daß bei externen
Funktionen kein 'extern' davor muß, wo doch bei externen Daten
selbiges notwendig ist?
Nö, muß man nicht.
W.S.
W.S. schrieb:> Muß man also im Jahre 2019 noch auswendig lernen, daß bei externen> Funktionen kein 'extern' davor muß, wo doch bei externen Daten selbiges> notwendig ist?
Ja, kann man so sehen.
Geht aber auch pragmatischer: da die Funktionsdeklaration auch ohne
extern eindeutig ist, kann dies weggelassen werden. Das hat sich bei
vielem anderen auch bewährt, z.b. init mit 0, auto, long int, ... .
Ja, man kann Pendant sein. Aber im Long Run gewinnt hier das
pragmatische bei Aufwand/Nutzen
W.S. schrieb:> Muß man also im Jahre 2019 noch auswendig lernen, daß bei externen> Funktionen kein 'extern' davor muß, wo doch bei externen Daten selbiges> notwendig ist?
Da es bei Funktionen das Konzept der Vorwärtsdeklaration (durch den
Funktionsprototypen) gibt, wird man diese kognitive Leistung wohl
aufbringen müssen. Wie man im Leben überhaupt oft irgendwelche Dinge
lernen muss.
Immerhin:
Ein überflüssiges "extern" richtet keinen Schaden an, außer zu
vermitteln, daß derjenige, der es verwendet hat, nicht so recht
verstanden hat, was es bedeutet.
Rufus Τ. F. schrieb:> Ein überflüssiges "extern" richtet keinen Schaden an, außer zu> vermitteln, daß derjenige, der es verwendet hat, nicht so recht> verstanden hat, was es bedeutet.
Ok, ab sofort darfst du keine avr-libc mehr verwenden :-)
Johann L. schrieb:> Rufus Τ. F. schrieb:>> Ein überflüssiges "extern" richtet keinen Schaden an, außer zu>> vermitteln, daß derjenige, der es verwendet hat, nicht so recht>> verstanden hat, was es bedeutet.>> Ok, ab sofort darfst du keine avr-libc mehr verwenden :-)
Es ist schon lustig, wie aus
"es muß nicht dastehen, weil es sich aus dem Kontext eh eindeutig
ergibt"
zu
"es darf nicht verwendet werden"
wird.
Aber wenn das die wichtigsten Probleme sind, dann geht es uns ja
wenigstens gut. ;-)
Carl D. schrieb:> Johann L. schrieb:>> Rufus Τ. F. schrieb:>>> Ein überflüssiges "extern" richtet keinen Schaden an, außer zu>>> vermitteln, daß derjenige, der es verwendet hat, nicht so recht>>> verstanden hat, was es bedeutet.>>>> Ok, ab sofort darfst du keine avr-libc mehr verwenden :-)>> Es ist schon lustig, wie aus "es muß nicht dastehen, weil es sich> aus dem Kontext eh eindeutig ergibt" zu "es darf nicht verwendet> werden" wird.
Na wenn Carl meint, dass die avr-libc Autoren planlos waren und keine
Ahnung von dem, was sie da fabrizierten, wird er diese Software kaum
verwenden wollen...
Johann L. schrieb:> Na wenn Carl meint, dass die avr-libc Autoren planlos waren und keine> Ahnung von dem, was sie da fabrizierten,
Ob Carl das meint?
Ich jedenfalls stehe dazu, daß ich "extern" bei Funktionsdeklarationen
für überflüssig halte und daß ich der Ansicht bin, daß Leute, die es
verwenden, nicht so recht verstanden haben, was es bedeutet.
Wenn die avr-libc so geschrieben ist, sei es drum. Es macht sie nicht
unbrauchbar, es ... verwundert nur etwas.
(Es gibt auch durchaus professionell verwendbare Software, die von
Leuten mit merkwürdigen Ansichten und Designentscheidungen geschrieben
wurde)
In C ist jede Funktion extern in dem Sinn, dass sie außerhalb jeder
anderen Funktion definiert wird¹. Das Schlüsselwort extern bezieht
sich auf genau diese Eigenschaft und nicht – wie oft irrtümlicherweise
angenommen – darauf, dass die deklarierte Funktion in einer anderen
Übersetzungseinheit definiert ist.
Betrachten wir die beiden folgenden Deklarationen:
1
voidf(void);
und
1
externvoidf(void);
Mit der ersten drückt man (vereinfacht) aus:
"Ich möchte die Funktion f benutzen."
Mit der zweiten hingegen:
"Ich möchte von allen Funktionen namens f diejenige benutzen, die
außerhalb aller anderen Funktionen definiert wurde."
Da die Zusatzbedingung im zweiten Fall trivialerweise immer erfüllt ist,
ist sie – und damit auch das extern – überflüssig.
Da es (fast immer) egal ist, ob man das extern vor Funktionsprototypen
benutzt oder nicht, besteht die Möglichkeit, es zu Dokumentationszwecken
zu nutzen:
- Funktionen, die in mehreren Übersetzungseinheiten genutzt werden (also
insbesondere auch Bibliothekfunktionen), werden als extern
deklariert (auch wenn dies nicht der eigentlichen Bedeutung des
Schlüsselworts entspricht.
- Bei Funktionen, die nur innerhalb einer einzigen Übersetzungseinheit
genutzt werden, wird das extern weggelassen.
Diese Vorgehensweise scheint in mehreren prominenten Quellen wie bspw.
- der ISO-Norm,
- dem GCC und
- der GNU C Library (glibc)
zur Anwendung zu kommen.
Ich persönlich halte davon dennoch nicht viel, da man die Unterscheidung
der beiden o.g. Fälle ebenso gut durch die Verwendung bzw. das Weglassen
von static erreicht. Da die Verwendung von static für dateilokale
Funktionen aus Kapselungs- und Optimierungsgründen ohnehin ratsam ist,
erschlägt man damit gleich zwei FLiegen mit einer Klappe.
M.W. gibt es in C nur einen einzigen Fall, wo extern in einer
Funktionsdelaration einen semantischen Unterschied macht, nämlich in
Verbindung mit einer inline-Deklaration:
Mit
1
inlinevoidf(void){
2
// ...
3
}
wird eine so genannte "inline definition" der Funktion f angelegt. Damit
kann die Funktion zwar geinlinet, aber weder per Call aufgerufen noch
per Funktionszeiger referenziert werden.
Fügt man hingegen ein extern hinzu, erzeugt der Compiler eine
"external definition", so dass f auch wie jede Nicht-Inline-Funktion
genutzt werden kann:
1
externinlinevoidf(void){
2
// ...
3
}
Allerdings wird man diese Methode, eine external Definition zu erzeugen,
aus den folgenden Gründen in der Praxis kaum nutzen:
- Wird f nur in einer einzigen Übersetzungseinheit genutzt, wird man es
als static inline deklarieren. Dadurch wird ebenfalls eine external
Definition erzeugt, wobei der erzeugte Programmcode ggf. vom Compiler
wieder wegoptimiert wird.
- Wird f in mehreren Übersetzungseinheiten genutzt, schreibt man die
Inline-Definition von f in ein .h-File. Man kann f dort wie oben als
static inline deklarieren, oder man deklariert es nur als inline
und schreibt für die Erzeugung der external Definition eine weitere
Deklaration in eines der .c-Files:
1
externvoidf(void);
Hier kann man wiederum das extern weglassen und einfach
1
voidf(void);
schreiben.
Aus den genannten Gründen verwende ich in Funktionsdeklarationen
grundsätzlich kein extern, kritisiere aber nicht diejenigen mit
diesbezüglich anderen Vorlieben. Letztendlich ist das eine Frage des
persönlichen Programmierstils, der sich bei Weitem nicht nur auf solche
Kleinigkeiten beschränkt.
———————————————
¹) Anders als bspw. Pascal erlaubt ISO-C keine verschachtelten
Funktionsdefinitionen. In C gibt es diese Möglichkeit allenfalls als
Spracherweiterung, wie bspw. beim GCC.
Yalu X. schrieb:> In C ist jede Funktion extern in dem Sinn, dass sie außerhalb jeder> anderen Funktion definiert wird¹. Das Schlüsselwort extern bezieht> sich auf genau diese Eigenschaft und nicht – wie oft irrtümlicherweise> angenommen – darauf, dass die deklarierte Funktion in einer anderen> Übersetzungseinheit definiert ist.
Dass extern in C darauf zurückgeht, dass eine Funktion außerhalb aller
anderen Funktionen definiert wurde, dem würde ich widersprechen. I.W
bezieht sich extern auf die Linkage von Identifiern:
Objekte und Funktionen werden in C mit Identifiern bezeichnet, und der
maximale Gültigkeitsbereich / Sichtbarkeit eines Identifiers ist eine
Compilation Unit. Um von einer Compilation Unit auf eine in einer
anderen Unit definierten Entity zuzugreifen, gibt es in C das Konzept
der external Linkage. Mit external Linkage werden quasi Identifier (auf
Object-Ebene: Symbole) aus unterschiedlichen Compilation Units
miteinander verbunden.
Weil der maximale Gültigkeitsbereich eines Identifiers eine Compilation
Unit ist, wäre die natürliche Bedeutung von "void f(void);" internal
Linkage, also wie bei "static void f(void);" :-)
> Ich persönlich halte davon dennoch nicht viel, da man die Unterscheidung> der beiden o.g. Fälle ebenso gut durch die Verwendung bzw. das Weglassen> von static erreicht.
Mit static hat man aber eine andere Linkage, und es ist nicht mehr
möglich, die Entity aus anderen Compilation Units aus zu referenzieren.
Man trifft damit also eine weitreichende Design-Entscheidung.
Zudem wird man eine extern Decl in den Header schreiben, also in die
Interface-Beschreibung eines Moduls, eine static Decl aber im C-Modul
selbst haben wollen. In einem Header kann eine static Decl sogar fatal
sein, weil diese es unmöglich macht, in einer anderen Unit, die den
Header verwendet, eine lokale Entity gleichen Namens aber anderen
Interfaces zu definieren.
> M.W. gibt es in C nur einen einzigen Fall, wo extern in einer> Funktionsdelaration einen semantischen Unterschied macht, nämlich in> Verbindung mit einer inline-Deklaration:> > Mit> > inline void f(void) {> // ...> }> > wird eine so genannte "inline definition" der Funktion f angelegt. Damit> kann die Funktion zwar geinlinet, aber weder per Call aufgerufen noch> per Funktionszeiger referenziert werden.
Doch, das geht beides. inline ist eine höfliche Bitte an den Compiler,
den Code zu inlinen. Wird z.B. die Adresse der Funktion genommen, ist
das kein Problem. Ob eine Instanz der Funktion erstellt wird, und mit
welcher Linkage, hängt mit der inline-Variante zusammen.
> Fügt man hingegen ein extern hinzu, erzeugt der Compiler eine> "external definition", so dass f auch wie jede Nicht-Inline-Funktion> genutzt werden kann:> > extern inline void f(void) {> // ...> }> > Allerdings wird man diese Methode, eine external Definition zu erzeugen,> aus den folgenden Gründen in der Praxis kaum nutzen:>> - Wird f nur in einer einzigen Übersetzungseinheit genutzt, wird man es> als static inline deklarieren. Dadurch wird ebenfalls eine external> Definition erzeugt, wobei der erzeugte Programmcode ggf. vom Compiler> wieder wegoptimiert wird.
Nö. static inline hat internal Linkage, d.h. die Funktion kann von
anderen Compilation Units nicht referenziert werden. Hat man eine
static inline Funktion in einem Header, dann erzeugt diese in den
unterschiedlichen Units, die den Header verwenden, Funktionen, die
formal nichts miteinander zu tun haben — sie haben lediglich den
gleichen Code und den gleichen Namen und die gleiche (internal) Linkage.
Dass die Linkage internal ist, sieht man etwa wenn man folgendes
Beispiel compiliert:
1
staticinlinevoidf(void){}
2
3
void(*use(void))(void)
4
{
5
returnf;
6
}
> - Wird f in mehreren Übersetzungseinheiten genutzt, schreibt man die> Inline-Definition von f in ein .h-File. Man kann f dort wie oben als> static inline deklarieren, oder man deklariert es nur als /inline/> und schreibt für die Erzeugung der external Definition eine weitere> Deklaration in eines der .c-Files:>> extern void f(void);
Schön verwirrend, weil hier eine Deklaration dazu führt, dass der
Compiler die Funktion instanziiert :-)
Anwendungsfall wäre, wenn man stark davon ausgehen muss, dass gerne die
Adresse der Funktion genommen wird (oder es andere Gründe gibt, warum
nicht geinlinet wird wie Optimierung), und man dabei mehrere Instanzen
wie bei static inline vermeiden will.
Johann L. schrieb:> Dass extern in C darauf zurückgeht, dass eine Funktion außerhalb aller> anderen Funktionen definiert wurde, dem würde ich widersprechen. I.W> bezieht sich extern auf die Linkage von Identifiern:
Eine extern-Deklaration kann, muss sich aber nicht auf einen Identifier
mit external Linkage beziehen. Ein Beispiel hast du ja oben schon
genannt:
> Übrigens bedeutet das extern nicht notwendigerweise, dass function> external Linkage hat, insbesondere wenn eine static Deklaration /> Definition dem extern vorausgeht:> static int f (void);> extern int f (void);
Außerdem gab es das Schlüsselwort extern schon lange vor der Einführung
von static auf File-Scope und der damit verbundenen Begriffe external/
internal Linkage.
>> Ich persönlich halte davon dennoch nicht viel, da man die Unterscheidung>> der beiden o.g. Fälle ebenso gut durch die Verwendung bzw. das Weglassen>> von static erreicht.>> Mit static hat man aber eine andere Linkage, und es ist nicht mehr> möglich, die Entity aus anderen Compilation Units aus zu referenzieren.
Genau das will man
Yalu X. schrieb:> Bei Funktionen, die nur innerhalb einer einzigen Übersetzungseinheit> genutzt werden
ja auch gar nicht.
> Zudem wird man eine extern Decl in den Header schreiben, also in die> Interface-Beschreibung eines Moduls, eine static Decl aber im C-Modul> selbst haben wollen.
Klar, dem widerspreche ich auch überhaupt nicht.
>> Mit>>>> inline void f(void) {>> // ...>> }>>>> wird eine so genannte "inline definition" der Funktion f angelegt. Damit>> kann die Funktion zwar geinlinet, aber weder per Call aufgerufen noch>> per Funktionszeiger referenziert werden.>> Doch, das geht beides. inline ist eine höfliche Bitte an den Compiler,> den Code zu inlinen.
Wenn er dieser Bitte aber nicht entspricht und stattdessen einen Call
generiert, meckert bei obiger Deklaration der Linker das unaufgelöste
Symbol f an.
> Wird z.B. die Adresse der Funktion genommen
Das ergibt die gleiche Linkermeldung wie beim Call. Erst mit einer
static- oder extern-Deklaration wird aufrufbarer Code für die Funktion
erzeugt.
>> - Wird f nur in einer einzigen Übersetzungseinheit genutzt, wird man es>> als static inline deklarieren. Dadurch wird ebenfalls eine external>> Definition erzeugt, wobei der erzeugte Programmcode ggf. vom Compiler>> wieder wegoptimiert wird.>> Nö. static inline hat internal Linkage, d.h. die Funktion kann von> anderen Compilation Units nicht referenziert werden.
Deswegen schrieb ich ja
Yalu X. schrieb:> Wird f nur in einer einzigen Übersetzungseinheit genutzt, ...
Oder schmeißt du jetzt "external Definition" unbd "external Linkage"
durcheinander? Das sind zwei völlig verschiedene Dinge. Eine mit static
definierte Funktion auf File-Scope hat internal Linkage, aber eine
external Definition. Das "external" bei "Linkage" bezieht sich auf die
Ausweitung auf andere Übersetzungseinheiten, das "external" bei der
"Definition" bedeutet aber "außerhalb jeder Funktion".
> Anwendungsfall wäre, wenn man stark davon ausgehen muss, dass gerne die> Adresse der Funktion genommen wird (oder es andere Gründe gibt, warum> nicht geinlinet wird wie Optimierung), und man dabei mehrere Instanzen> wie bei static inline vermeiden will.
Genau so ist es.
Ach ihr diskutiert ja noch immer - und gerade die Beiträge von Yalu
werden immer schwurbeliger. "Extern in dem Sinne daß.. - in diesem Sinne
ist jede.. bezieht sich auf..." und sonstige Schwurbeleien.
Mannomann, geht's noch?
Klar ist, daß C keine lokalen Funktionen und Prozeduren kennt wie z.B.
Algol und Pascal sie seit Urzeiten kennen. Sowas ist ein Manko von C,
aber man kann damit so lala leben. Ein Vorzug ist dieses Fehlen jedoch
nicht gerade.
Mir kommt da so ein Honecker-Spruch (oder einer von Karl-Eduard von
Knacks) in den Sinn: Diese Knallköpfe definierten "Freiheit" im Sinne
von "Keimfreiheit" - also der Abwesenheit von dem, was jeder noch
logisch denkende Mensch unter Freiheit versteht - naja, nur so lange wie
die Mauer gehalten hat. Reisefreiheit = Abwesenheit der Möglichkeit zu
reisen, gelle?
Und Yalu's Beiträge zum Thema "extern" klingen fast genau so. Eben ein
Versuch der Sinnesverdrehung!
Nochmal: extern heißt schlichtweg: hier nicht vorrätig, sondern in einer
anderen Quelle vorhanden - nämlich der, zu welcher diese Headerdatei
gehört. Ohne diese einfach zu verstehende Grundbedeutung könnte man sich
jegliche Headerdatei sonstwohin schmieren. Und nix von wegen "Extern im
Sinne von.."
A. S. schrieb:> Geht aber auch pragmatischer: da die Funktionsdeklaration auch ohne> extern eindeutig ist, kann dies weggelassen werden.
Klar, man kann es in diesem speziellen Falle weglassen - aber SOLLTE
man es in diesem speziellen Falle weglassen?
Ich sage dazu ein klares NEIN, denn das Ausmerzen von überflüssigen
Besonderheiten und Extrawürsten hat gerade C nötig - man braucht einen
Sonderfall weniger zu beachten.
Genau DARIN liegt auf lange Sicht der Fortschritt. So rein theoretisch
ließe sich selbst C durchaus noch modernisieren und auf den Stand von
2019 bringen - aber dazu müßte man eben genau so, wie damals ANSI mit
der Machete durch's K&R-Gestrüpp hauen - ungeachtet des Gelabers der
Leute, die mit schwülstigen Reden alte Designfehler als "besondere
Bedeutung" den Leuten verkaufen wollen wie Yalu oder jedem, der den
Mißstand kritisiert oder gar zumindest formal behebt, als unwissend zu
bezeichnen - wie z.B. Rufus mal wieder:
Rufus Τ. F. schrieb:> Da es bei Funktionen das Konzept der Vorwärtsdeklaration (durch den> Funktionsprototypen) gibt, wird man diese kognitive Leistung wohl> aufbringen müssen.
Nö, muß man überhaupt nicht. Stattdessen muß man - wenn es mit der
Menschheit vorangehen soll - die besagte Machete zücken und den alten
Unsinn heraushacken.
So herum!
Und:
Jawoll, es geht.
Ja, es geht tatsächlich mit allen mir bekannten Compilern.
Voila!
W.S.
W.S. schrieb:> Klar ist, daß C keine lokalen Funktionen und Prozeduren kennt wie z.B.> Algol und Pascal sie seit Urzeiten kennen. Sowas ist ein Manko von C,> aber man kann damit so lala leben. Ein Vorzug ist dieses Fehlen jedoch> nicht gerade.
Wozu braucht man das? Ich hab's noch nie vermisst, und ich habs auch nie
benutzt, als ich noch in Pascal programmiert habe.
> A. S. schrieb:>> Geht aber auch pragmatischer: da die Funktionsdeklaration auch ohne>> extern eindeutig ist, kann dies weggelassen werden.>> Klar, man kann es in diesem speziellen Falle weglassen - aber SOLLTE> man es in diesem speziellen Falle weglassen?
Es ist kein "spezieller Fall", denn es geht nicht um eine einzelne, ganz
bestimmte Funktion, sondern um alle.
> Ich sage dazu ein klares NEIN, denn das Ausmerzen von überflüssigen> Besonderheiten und Extrawürsten hat gerade C nötig - man braucht einen> Sonderfall weniger zu beachten.
Was ist daran "Sonderfall"? Ich schreibe eine Deklaration einer Funktion
hin, und die gilt per Default als extern. Eigentlich gibt's nur zwei
Fälle, nämlich Funktionen und Variablen. Und wenn schon, dann sind für
mich die Variablen eher der Sonderfall, da es hier nur aus einem Grund
nötig ist, das "extern" explizit hinzuschreiben: Um eine Definition
überhaupt von einer reinen Deklaration unterschieden zu können. Denn
ohne das "extern" wäre es eine Definition.
Rufus Τ. F. schrieb:> Ich jedenfalls stehe dazu, daß ich "extern" bei Funktionsdeklarationen> für überflüssig halte und daß ich der Ansicht bin, daß Leute, die es> verwenden, nicht so recht verstanden haben, was es bedeutet.
Und andere Leute sind dazu eben anderer Ansicht. Ich habe schon oft
"extern" explizit hingeschrieben, wenn es als eine Art
Import-Deklaration gemeint war, die es in C leider nicht formal gibt.
Analog dazu sehe ich es als Geburtsfehler von C an, dass Funktionen wie
Daten implizit global sind, statt implizit auf die compilation unit
bezogen.
Hugo schrieb:> Wenn du mal irgendwann Langeweile haben solltest, kannst du gerne mal> ein C-Buch lesen ;-)
Und auf den ersten 100 Seiten steht es genau so da, wie Ralph es
beschrieben hat.
Rolf M. schrieb:> Und wenn schon, dann sind für> mich die Variablen eher der Sonderfall, da es hier nur aus einem Grund> nötig ist, das "extern" explizit hinzuschreiben: Um eine Definition> überhaupt von einer reinen Deklaration unterschieden zu können. Denn> ohne das "extern" wäre es eine Definition.
Wobei das aus historischen Gründen bei Variablen etwas komplizierter
sein kann, wenn man reale Compiler in deren Default-Einstellung
betrachtet. Die ein einfaches "int a;" in mehreren compilation units
zulassen, und bei denen dies im Fall eines weiteren "int a = 1;" von
einer verteilten Definition zu einer Deklaration wird.
Ralph S. schrieb:> In file2.c verwendest du function(), die in file2.c nicht definiert ist.> Wäre function() nicht als extern deklariert. würde der Compiler den Code> für function() in der Datei file2.c suchen und dort nicht finden, weil> nicht vorhanden. file2.c wäre somit nicht compilierbar.
Schon ausprobiert? ;-)
Ist mit GCC ohne Optionen compilierbar:
1
voidf(void)
2
{
3
function();
4
}
K&R-C lässt grüssen. Mit -Wall gibts "warning: implicit declaration of
function ‘function’ [-Wimplicit function-declaration] function();".
W.S. schrieb:> Nochmal: extern heißt schlichtweg: hier nicht vorrätig, sondern in einer> anderen Quelle vorhanden
Nochmal: Dies ist schlichtweg falsch.
Im C-Standard¹ auf S. 29 heißt es in §6.2.2-5:
> If the declaration of an identifier for a function has no storage-class
specifier, its linkage is determined exactly as if it were declared with the
storage-class specifier extern .
Das "extern" ist also immer impliziert, es sei denn man schreibt
"static" oder "inline". Eine Deklaration ohne "static" und "inline",
aber egal ob mit "extern" oder ohne, bedeutet immer, dass _genau
eine_ Definition entweder in der selben oder einer anderen
Translation Unit auftaucht.
W.S. schrieb:> Diese Knallköpfe definierten "Freiheit" im Sinne> von "Keimfreiheit" - also der Abwesenheit von dem, was jeder noch> logisch denkende Mensch unter Freiheit versteht
Das war dann wohl von Orwell und Neusprech abgeschaut.
W.S. schrieb:> Genau DARIN liegt auf lange Sicht der Fortschritt. So rein theoretisch> ließe sich selbst C durchaus noch modernisieren und auf den Stand von> 2019 bringen
Dann erhält man aber eine komplett andere Sprache, welche zu bestehenden
Programmen und Tools inkompatibel ist. Solche Sprachen gibt es, wie z.B.
Rust. Sie haben es sehr schwer, im Embedded-Umfeld akzeptiert zu werden,
weil große vorhandene Codebasen, Tools und Standards (z.B. MISRA) C
sind/voraussetzen.
Bei vielen Programmen/Bibliotheken/Tools heißt es doch sogar: ANSI-C
kompatibel, d.h. zum allerersten offiziellen C-Standard von 1989. Selbst
der gleichwertige, neuere "internationale" Name ISO-C90 wird ignoriert,
und alle folgenden neueren Standards (C99, C11, C17) sowieso. Die
Industrie scheint sich darauf geeinigt zu haben, dass ANSI-C die einzig
wahre Programmiersprache ist und niemals etwas neues akzeptabel sein
wird.
1: Draft:
https://web.archive.org/web/20181230041359if_/http://www.open-std.org/jtc1/sc22/wg14/www/abq/c17_updated_proposed_fdis.pdf
Die Verwirrung rührt u.A. auch daher, dass Ritchie ursprünglich "extern"
ausschliesslich als Linkage vorsah, ohne Bezug auf Speicherzuordnung.
Dadurch war "extern" ausserhalb von Funktionen vollständig redundant,
egal ob bei Daten oder bei Funktionen.
In seinem Compiler reichte folglich
extern int a;
aus, um Storage zu definieren. Das war in sich konsistent, aber nicht
auf allen Plattformen implementierbar, weil es auf der Linker-Ebene
analog zu FORTRAN COMMON Records unterstützt werden muss.
Andere Compiler-Autoren interpretierten C anders. Bei Daten änderte sich
die Rolle von "extern" etwas, bei Funktionen blieb sie unverändert.
ANSI-C legte sich in diese Richtung fest, verwarf Ritchies Prinzip.
Siehe C99 Rationale 6.2.2.
W.S. schrieb:> Und Yalu's Beiträge zum Thema "extern" klingen fast genau so. Eben ein> Versuch der Sinnesverdrehung!>> Nochmal: extern heißt schlichtweg: hier nicht vorrätig, sondern in einer> anderen Quelle vorhanden
Wie kommst du darauf? Es gibt in C keine Möglichkeit, explizit auf ein
Symbol in einer anderen Quelle zu verweisen, und schon gar nicht
geschieht dies mit extern.
Du kannst das im ISO-Dokument nachlesen, allerdings musst du dazu die
Informationen von mehreren Textstellen zusammentragen, da es keinen
Abschnitt speziell zu extern gibt, in dem dieses in allen Details
zusammenfassend beschrieben wird. Erschwerend kommt hinzu, dass das
Schlüsselwort extern weitere Funktionen hat, bspw. um eine reine
Deklaration von einer tentative Definition zu unterscheiden.
Um es dir etwas leichter zu machen, habe ich mal ein aus den Quellen
main.c und other.c bestehendes ISO-konformes Beispiel erstellt, aus dem
hervorgeht, dass du mit deiner obigen Vermutung daneben liegst:
main.c:
1
#include<stdio.h>
2
3
staticvoidf(void){
4
printf("static f in main.c\n");
5
}
6
7
intmain(void){
8
externvoidf(void);
9
f();
10
}
other.c:
1
#include<stdio.h>
2
3
voidf(void){
4
printf("f in other.c\n");
5
}
Nach deiner Theorie müsste der Aufruf von f in main() zur Definition in
other.c führen. Tatsächlich wird aber das in main.c definierte f
aufgerufen. Das liegt daran, dass die extern-Deklaration von f auf eine
external Definition von f verweist. Davon gibt es im Programm zwei,
nämlich eine in main.c und eine in other.c. Dabei verdeckt das f in
main.c seinen Namensvetter in other.c, weswegen die extern-Deklaration
in main() auf das f in main.c verweist.
Am besten liest du dir dazu Abschnitt 6.9 der ISO-Norm durch, in der
neben anderen wichtigen Dingen auch folgendes steht:
1
As discussed in 5.1.1.1, the unit of program text after preprocessing is
2
a translation unit, which consists of a sequence of external
3
declarations. These are described as ‘‘external’’ because they appear
4
outside any function (and hence have file scope). As discussed in 6.7, a
5
declaration that also causes storage to be reserved for an object or a
W.S. schrieb:> Nochmal: extern heißt schlichtweg: hier nicht vorrätig, sondern in einer> anderen Quelle vorhanden - nämlich der, zu welcher diese Headerdatei> gehört.
Wobei diese andere Quelle auch die gleiche Quelle sein kann, wenn es
nämlich um jene Quelle geht, die zum Include-File gehört. Nur kommt dann
eben noch zusätzlich die Funktionsdefinition hinzu, wodurch im
Include-File eine Vorwärtsdeklaration daraus wird, kein Verweis auf eine
andere Quelle.
Soviel zu Sprachschwurbelei. Wenn es um formale Standards (oder
juristische Aspekte) geht, ist exakte Ausdrucksweise wichtig, auch wenn
es dann etwas komplexer klingen kann.
Ausserdem beziehst du dich auf jene Form der Modularisierung, die man
beim Programmieren verwenden sollte, aber nicht auf die Sprache. Man
sollte auseinander halten, ob es um praktische Programmierung geht, oder
um die formale Sprache selbst.
A. K. schrieb:> Die Verwirrung rührt u.A. auch daher, dass Ritchie ursprünglich "extern"> ausschliesslich als Linkage vorsah, ohne Bezug auf Speicherzuordnung.> Dadurch war "extern" ausserhalb von Funktionen vollständig redundant,> egal ob bei Daten oder bei Funktionen.
Ursprünglich gab es auf File-Scope für Funktionen gar kein extern. Das
wurde erst später als Option hinzugefügt, was offensichtlich keine so
gute Idee war, wie man an diesem Thread sieht :)
Dr. Sommer schrieb:> markus schrieb:> Warum sind die Funktionen als extern deklariert?>> Weil der Programmierer nicht wusste, dass "extern" bei Funktionen> komplett wirkungslos ist.
Falsche Schlussfolgerung. Ich weiß, dass "extern" bei Funktionen
komplett wirkungslos ist und schreibe es trotzdem hin.
Der Grund ist wahrscheinlich mein Hang zur Symmetrie. Hiermit meine ich
die externe Variablendeklaration, wo das extern natürlich notwendig ist.
Yalu X. schrieb:> As discussed in 5.1.1.1, the unit of program text after preprocessing> is a translation unit, which consists of a sequence of external> declarations. These are described as ‘‘external’’ because they appear> outside any function (and hence have file scope).
M.E. sollte man diese Verwendung "external" besser schnell vergessen,
wenn man jemand erklären will, was "extern" in C/C++ bedeutet oder
external Linkage.
Diese Verwendung mag bei vergleichender Analyse unterscheidlicher
Programmiersprachen hilfreich sein, aber in Kontexten wie im hiesigen
Thread ist dieses "external" einfach nur ne Nebelbombe, die das
Auseinanderdividieren von "extern" und external Linkage unnötig
erschwert.
Yalu X. schrieb:> Ursprünglich gab es...
.. nicht mal Namen in den Argumenten der Funktionen.
Wir sollten froh sein, daß per ANSI-C dieser üble K&R-Mist ausgemistet
worden ist. Also jammere nicht diesem Uralt-Zeugs hinterher und richt
deinen Blick lieber nach vorn und auf den derzeitigen Zustand dieser
Programmiersprache - da gibt es noch sehr viel auszumisten. Und das
Herumgeeiere wegen 'extern', was du hier dazu geschrieben hast, gehört
dazu.
Frank M. schrieb:> Ich weiß, dass "extern" bei Funktionen> komplett wirkungslos ist und schreibe es trotzdem hin.
Eins PLUS.
W.S.
W.S. schrieb:> Yalu X. schrieb:>> Ursprünglich gab es...>> .. nicht mal Namen in den Argumenten der Funktionen.>> Wir sollten froh sein, daß per ANSI-C dieser üble K&R-Mist ausgemistet> worden ist. Also jammere nicht diesem Uralt-Zeugs hinterher und richt> deinen Blick lieber nach vorn und auf den derzeitigen Zustand dieser> Programmiersprache
Ich jammere keinem Uralt-Zeugs hinterher, sondern bin mit dem aktuellen
Stand von C mehr zufrieden denn je. Ein paar Dinge (die nicht Gegenstand
dieses Threads sind) sind aus historischen Gründen zwar etwas krumm,
aber auch damit kann ich ganz gut leben.
> - da gibt es noch sehr viel auszumisten. Und das Herumgeeiere wegen> 'extern', was du hier dazu geschrieben hast, gehört dazu.
Ich persönlich hätte überhaupt kein Problem damit, das extern komplett
auszumisten, nicht nur für Funktionen, sondern auch für Objekte. Es war
von Anfang an ein Work-Around, der in Verbindung mit den Erweiterungen
in späteren C-Versionen für viele immer unverständlicher wurde. Dabei
wird er auf den meisten aktuellen Plattformen gar nicht (mehr) benötigt.
Da du selber aber an dieser Altlast zu hängen scheinst, finde ich es
auch nicht schlimm, wenn das extern beibehalten wird. Ich weiß, wie
damit umzugehen ist, und das allein ist für mich wichtig. Und wenn du
Probleme damit hast¹, ist das zwar schade, aber zum Glück sind deine
Probleme nicht meine ;-)
—————————————
¹) und die scheinst du mit allem zu haben, was auch nur einen µm von
deinem heißgeliebten Object-Pascal abweicht
Yalu X. schrieb:> Dabei wird er auf den meisten aktuellen Plattformen gar nicht (mehr) benötigt.
auch nicht für Variablen? Was wäre da der Ersatz für extern? Oder
meintest Du das Beispiel mit den Funktionen f und extern f?
A. S. schrieb:> Yalu X. schrieb:>> Dabei wird er auf den meisten aktuellen Plattformen gar nicht (mehr) benötigt.> auch nicht für Variablen? Was wäre da der Ersatz für extern? Oder> meintest Du das Beispiel mit den Funktionen f und extern f?
Nimm ein beliebiges C-Programm, entferne darin sämtliche extern (auch
in Variablendeklarationen), baue es neu, führe es aus und wundere dich.
ABER: Aus Portabilitätsgründen solltest du dich keineswegs darauf
verlassen, dass das immer so ist. Es sind zwar offiziell mehrere gleiche
temptative Definitions (d.h. globale Variablendeklarationen ohne
extern und ohne Initialisierung) innerhalb einer Übersetzungseinheit
erlaubt, nicht aber übergreifend über mehrere Übersetzungseinheiten.
Immerhin ist es im C11-Standard unter "Common extensions" aufgeführt, so
dass eine gewisse Chance besteht, dass es in einer zukünftigen C-Version
offiziell wird.
Yalu X. schrieb:> Nimm ein beliebiges C-Programm, entferne darin sämtliche extern (auch> in Variablendeklarationen), baue es neu, führe es aus und wundere dich.
Auch hier? ;-)
1
intf(void)
2
{
3
externinta;
4
returna;
5
}
Das ist die wohl einzige Stelle, an der "extern" immer notwendig ist.
Allerdings ist diese Art Code etwas schräg.
A. K. schrieb:> Auch hier? ;-)> int f(void)> {> extern int a;> return a;> }
Stimmt, da kann man das extern nicht weglassen.
> Das ist die wohl einzige Stelle, an der "extern" immer notwendig ist.
Die andere ist die Kombination mit inline:
Yalu X. schrieb:> extern inline void f(void) {> // ...> }A. K. schrieb:> Allerdings ist diese Art Code etwas schräg.
Die direkte Kombination mit dem inline ebenfalls. Beides wird man in
realem Code wohl so gut wie nie antreffen.
Stellt euch vor, es ist 2187. Der Warp-Antrieb wurde entwickelt. Die
Menschheit erkundet Alpha Centauri. Alle Krankheiten können geheilt
werden. Der letzte Windows XP-Rechner wird abgeschaltet. Es gibt keine
COBOL-Programme mehr. Und schließlich wird ein C-und-C++-Compiler
entwickelt, welcher keinerlei (Vorwärts-)Deklarationen mehr benötigt -
alle Programm-Elemente werden nur einmal in der .c/.cpp-Datei definiert,
Header-Dateien gibt es nicht mehr, der Compiler wird per
1
cc *.c *.cpp
aufgerufen, genau wie jetzt der "javac". Man darf noch träumen!
Yalu X. schrieb:> void f(void);>
…
> Mit der ersten drückt man (vereinfacht) aus:>> "Ich möchte die Funktion f benutzen."
Nö, das heißt nur, dass die Funktion f keinen Parameter hat und kein
Ergebnis zurück gibt.
Das f muss noch nichtmal definiert sein und von "benutzen" redet schon
gar keiner…
Yalu X. schrieb:> int main(void) {> extern void f(void);
Wusste gar nicht dass man in Funktionen andere Funktionen deklarieren
kann. Habe ich noch nie gesehen und macht wohl auch keiner aber dass das
überhaupt ohne Fehlermeldung compiliert hätte ich nicht gedacht.
Yalu X. schrieb:> Stimmt, da kann man das extern nicht weglassen.
ihr macht mich fertig :)
aber egal man lernt ja immer dazu.....
Ich hatte nie Funktionen in Header mit extern benannt, las aber irgendwo
das es "sauberer" sein soll, ich frag mich immer noch wieso?
In Header stehen ja keine Funktionen, nun bin ich gerade wieder mal am
programmieren, zu warm zum Löten und stolpere über meine extern
deklarierten Funktionen.
Also lösche ich alle extern vor Funktionen im Header und freue mich das
es nun später Tipparbeit spart.
Dr. Sommer schrieb:> Stellt euch vor, es ist 2187. ... schließlich wird ein C-und-C++-Compiler> entwickelt, welcher keinerlei (Vorwärts-)Deklarationen mehr benötigt -> alle Programm-Elemente werden nur einmal in der .c/.cpp-Datei definiert,
So lange sich das auf deinen eigenen Quelltext bezieht, wäre das heute
schon kein Problem. Compiler wie IBMs VisualAge C/C++ näherten sich dem
bereits vor vielen Jahren. Aber meistens gibt es noch weiteren Code, von
dem kein Quelltext vorliegt, also Libraries und Betriebssystem.
Irgendwelche Interface-Definitionen sind also unverzichtbar.
Dr. Sommer schrieb:> A. K. schrieb:>> Irgendwelche Interface-Definitionen sind also unverzichtbar.>> Java kommt auch ohne aus...
Wenn man den Quellcode von Software nicht hat, aber deren Funktionalität
verwenden will, dann muss für den Compiler irgendwo beschrieben sein,
wie das geht. Wenn mir der letzte Java-Update zur Allwissenheit nicht
entgangen ist, dann muss es also eine Interface-Beschreibung geben. Wie
auch immer die heisst.
A. K. schrieb:> Wenn mir der letzte Java-Update zur Allwissenheit nicht> entgangen ist, dann muss es also eine Interface-Beschreibung geben. Wie> auch immer die heisst.
Die ist bei java immer in den binären .class (.jar) Dateien enthalten.
Wenn das mal bei .lib/.so/.a/.dll Dateien auch so wäre...
Dr. Sommer schrieb:> Die ist bei java immer in den binären .class (.jar) Dateien enthalten.> Wenn das mal bei .lib/.so/.a/.dll Dateien auch so wäre...
Na also. Es gibt weiterhin eine Interface-Definition, nur eben nicht als
getrenntes File auf Betriebssystem-Ebene.
>> Das ist die wohl einzige Stelle, an der "extern" immer notwendig ist.> Allerdings ist diese Art Code etwas schräg.
Aber nicht ohne Anwendungsfall, zum Beispiel wenn man ein Symbol
verwenden will, das im Linkerskript definiert wird oder per --defsym auf
der Komandozeile. Vorstellbar etwa wenn man eine Checksumme über den
Programmcode berechnen will:
1
intcrc(void)
2
{
3
externbyte__code_start[];
4
externbyte__code_end[];
5
...
6
}
Allerdings könnte man das Zeig ebenso vor der Funktion deklarieren, ich
seh da jetzt kein Killerargument. Zwar bleiben die Deklarationen dann
auch hinter crc() gültig, aber man wird eh keine anderen, kollidierenden
Deklarationen haben.
Yalu X. schrieb:> Ich persönlich hätte überhaupt kein Problem damit, das extern komplett> auszumisten, nicht nur für Funktionen, sondern auch für Objekte.
Ach ja: Objekte in C.
Yalu X. schrieb:> Nimm ein beliebiges C-Programm, entferne darin sämtliche extern (auch> in Variablendeklarationen), baue es neu, führe es aus und wundere dich.
Du Witzbold!
Wenn schon, dann auch alle #include's entfernen, denn genau dort
findest du all die von dir verachteten 'extern's.
Dein Herumgeeiere geht offenbar in die nächste Runde. Jetzt fänst du
schon an, bei C von Objekten zu reden.
W.S.
W.S. schrieb:> Yalu X. schrieb:>> Ich persönlich hätte überhaupt kein Problem damit, das extern komplett>> auszumisten, nicht nur für Funktionen, sondern auch für Objekte.>> Ach ja: Objekte in C.
Was ist damit?
> Dein Herumgeeiere geht offenbar in die nächste Runde. Jetzt fänst du> schon an, bei C von Objekten zu reden.
Offenbar weißt du nicht, was C unter Objekten versteht. Das macht ja
erstmal nichts, aber dann solltest du dieses Unwissen nicht ganz so
offen zur Schau stellen.