Sina Anargo schrieb:> ist> extern void f(){};>> eine Deklaration oder Definition oder beides?
Keins von beiden, da das Semikolon hier nicht erlaubt ist. Ohne
Semikolon wäre es beides, da es sich um eine Definition handelt und jede
Definition automatisch auch eine Deklaration ist. Das 'extern' ist
überflüssig.
mir_fällt_keiner_ein schrieb:> Erst wenn in den geschweiften Klammern etwas steht, wird die Funktion> auch definiert. Ansonsten ist es nur eine Deklaration.
Wie kommst du auf den Unsinn? Ob die Funktion leer ist oder nicht,
spielt keine Rolle.
Rolf Magnus schrieb:> Keins von beiden, da das Semikolon hier nicht erlaubt ist.
Wieso ist das Semikolon nicht erlaubt?
danke schonmal fuer die antworten
Sina Anargo schrieb:> Wieso ist das Semikolon nicht erlaubt?
Weil das in der C Syntax offiziell nicht erlaubt ist. Man hätte es
erlauben können, hat es aber nicht getan.
Wenn ein Compiler es zulässt, heisst das nicht auch, dass C es zulässt.
Rolf Magnus schrieb:> Keins von beiden, da das Semikolon hier nicht erlaubt ist.
Schon, das Semikolon gehört aber nicht zur bereits vollständig
abgeschlossenen Funktionsdefinition. (A.K. mit -pendantic enabled ;-)
Ingo schrieb:> Aber warum extern für einen Funktionsprototypen?
ich wollte "extern" richtig verstehen. Ursprünglich habe ich das von dem
folgenden wie ich finde sehr schönen Trick:
include.h
1
#ifndef INLINE
2
#define INLINE extern inline
3
#endif
4
5
INLINEvoidf(){};
main.c
1
#define INLINE inline
2
#include"include.h"
alle anderen *.c
1
#include"include.h"
- Damit steht in der main.c inline void f(){} -> wird somit definiert
- während in allen anderen files steht extern inline void f(){} steht ->
wird somit nur deklariert.
daraus habe ich gefolgert, dass extern eine Deklaration forciert, wenn
der Funktionsbauch dabei steht. Gleich mal ohne inline ausprobiert, ob
meine These stimmt:
main.h
1
externvoidf(){};//ist ja nur deklaration nach meiner these
compiliert und siehe: Fehlermeldung "Symbol f multiply defined..."
also doch definition... aber beim inlinen irgendwie anders??
Schlussfolgerung ich hab da irgendwas nicht richtig verstanden. Aber
wie ist es denn nun genau?
Rolf Magnus schrieb:> Norbert schrieb:>> // gcc -Wall -Wextra -o x x.c>> Und jetzt probiere das selbe mal mit -pedantic.
Ahhh, sehr schön. Wieder etwas gelernt.
Sina Anargo schrieb:> Schlussfolgerung ich hab da irgendwas nicht richtig verstanden. Aber> wie ist es denn nun genau?
Es sind
extern int variable;
extern void f(void);
reine Deklarationen und
int variable;
int variable = 1;
void f(void) { }
reine Definitionen.
Sinnarme Mischformen wie
extern int variable = 1;
extern void f(void) { }
sollte man lieber nicht verwenden. Das ist zwar rein syntaktisch kein
Problem und eindeutig Definition, aber bestenfalls toleriert.
Es gab freilich auch Zeiten, da war in der Praxis
int variable;
bei vielen Compilern sowohl Deklaration wie Definition, je nachdem was
anderswo im Programm zum Thema "variable" vorkam.
Sina Anargo schrieb:> ich wollte "extern" richtig verstehen.
"extern" bei Funktionsdeklarationen ist immer überflüssig: man darf
es zwar schreiben, aber es gibt keinen Unterschied zur gleichen
Deklaration ohne "extern".
A. K. schrieb:> Es gab freilich auch Zeiten, da war in der Praxis> int variable;> bei vielen Compilern sowohl Deklaration wie Definition, je nachdem was> anderswo im Programm vorkam.
Dieses Verhalten wird vom Standard nach wie vor als eine von beiden
möglichen Verhaltensoptionen akzeptiert. Es ist eben nur schlechter
Stil, sich darauf zu verlassen, und spätestens, wenn man eine Variable
auch initialisieren will, kommt man um eine saubere "extern"-Deklaration
nicht umnhin.
Also kann man zusammenfassend sagen
extern void f(){};
ist nach C standard verboten, aber je nach dem welchen Compiler man
nutzt, drücken diese auf unterschiedliche Weise ein Auge zu, so dass man
Compilerabhängig solche Tricks wie mit dem extern inline oben
konstruieren kann... funktioniert aber eben nicht mit jedem Compiler
(zumindest kann man sich nicht sicher sein).
Und da das alles Compilerabhängig ist, braucht man nicht weiter über
eine tiefere Logik von extern nachdenken??
Sina Anargo schrieb:> - während in allen anderen files steht extern inline void f(){} steht ->> wird somit nur deklariert.
Mit "inline" ist das wieder eine andere Baustelle, denn während
extern void f(void) {}
eine vollständige Definition ist, ist das bei
extern inline void f(void) {}
nicht der Fall: "An inline definition does not provide an external
definition for the function, and does not forbid an external definition
in another translation unit."
An dieser Stelle wird das Eis ziemlich dünn, auf dem man sich bewegt.
Sina Anargo schrieb:> also doch definition... aber beim inlinen irgendwie anders??> Schlussfolgerung ich hab da irgendwas nicht richtig verstanden. Aber> wie ist es denn nun genau?
Als Daumenregel könnte man zusammenfassen: Wenn 'extern' (welches
eigentlich eine Deklaration anzeigt) mit der Tatsache kollidiert, dass
etwas eine Definition sein könnte, dann "verliert" das extern und es ist
eine Definition.
Dieser Grundsatz klärt Dinge wie
1
externintWerte[]={1,2,3,4};
Das hier kann keine Deklaration sein, selbst wenn da ein extern
angeführt ist. Denn hier existiert eine Initialisierung und
Initialisierungen gibt es nur bei Definitionen. Daher verliert die
Deklaration und das ganze ist eine Definition.
Selbiges in deinem Fall mit der Funktion.
Karl Heinz schrieb:> Als Daumenregel könnte man zusammenfassen: Wenn 'extern' (welches> eigentlich eine Deklaration anzeigt) mit der Tatsache kollidiert, dass> etwas eine Definition sein könnte, dann "verliert" das extern und es ist> eine Definition.
Ausser bei "inline", denn
extern void f(void) {}
erzeugt eine global verfügbare Funktion, während
extern inline void f(void) {}
das nicht tut. ;-)
Karl Heinz schrieb:> Dieser Grundsatz klärt Dinge wie
Wobei das von GCC auch ohne jede Pendantik mit einer Warnung quittiert
wird. Bei Funktionen freilich stört ihn das Äquivalent nicht.
Sina Anargo schrieb:> Also kann man zusammenfassend sagen
... dass man so etwas wie ...
> extern void f(){};
... lieber nicht verwenden sollte. Mit oder ohne "inline".
A. K. schrieb:> Es sind
[...]
> int variable;> int variable = 1;> void f(void) { }> reine Definitionen.
Seit wann ist eine Definition keine Deklaration mehr?
> Es gab freilich auch Zeiten, da war in der Praxis> int variable;> bei vielen Compilern sowohl Deklaration wie Definition, je nachdem was> anderswo im Programm zum Thema "variable" vorkam.
Warum sollte es denn keine Deklaration mehr sein? Das hieße ja, daß
folgender Code fehlerhaft wäre:
Rolf Magnus schrieb:> Seit wann ist eine Definition keine Deklaration mehr?
In meiner Betrachtungsweise enthält eine Definition auch die Bedeutung
einer Deklaration. Insofern sehe ich keine Widerspruch. Aber ich sehe,
dass du genau wie ich auch ein -pendantic Flag hast. ;-)
> Warum sollte es denn keine Deklaration mehr sein?
Das bezog sich auf den Fall:
file1: int variable;
file2: int variable = 1;
Das in file1 ist nur dann eine Definition, wenn file2 fehlt. Mit file2
ist es eine Deklaration.
A. K. schrieb:> In meiner Betrachtungsweise enthält eine Definition auch die Bedeutung> einer Deklaration. Insofern sehe ich keine Widerspruch.
Nun gut, für mich bedeutet es, dass eine Definition auch eine
Deklaration ist. Aber ich hab verstanden, wie du es meinst.
> Das bezog sich auf den Fall:> file1: int variable;> file2: int variable = 1;> Das in file1 ist nur dann eine Definition, wenn file2 fehlt. Mit file2> ist es eine Deklaration.
Aber das war in genormtem C noch nie so, oder?
Jörg Wunsch schrieb:> "extern" bei Funktionsdeklarationen ist immer überflüssig: man darf> es zwar schreiben, aber es gibt keinen Unterschied zur gleichen> Deklaration ohne "extern".
Das ist falsch, denn für
1
extern void a(void);
2
extern void b(void);
3
4
void a(void)
5
{
6
}
7
8
static void b(void)
9
{
10
}
liefert nämlich der GCC die folgende Fehlermeldung:
:8:13: error: static declaration of ‘b’ follows non-static declaration
:2:13: note: previous declaration of ‘b’ was here
Andreas Schweigstill schrieb:> Das ist falsch, denn …
… dein Code ist falsch. Wenn sich Deklaration und Definition
widersprechen, ist das natürlich ein Fehler.
Deine Deklaration für b() muss natürlich auch "static" haben (statt
"extern"), aber das "extern" bei der für a() kannst du genauso gut
weglassen – nicht mehr und nicht weniger habe ich geschrieben.
Jörg Wunsch schrieb:> Andreas Schweigstill schrieb:>> Das ist falsch, denn …>> … dein Code ist falsch. Wenn sich Deklaration und Definition> widersprechen, ist das natürlich ein Fehler.
...was aber zeigt, dass eine extern-Deklaration eben nicht immer
überflüssig ist. Denn:
Wenn sie immer überflüssig wäre, könnte man sie immer weglassen,
ohne dass sich was ändert. Ist bei Anderas' Beispiel aber nicht der
Fall.
Johann L. schrieb:> Wenn sie immer überflüssig wäre, könnte man sie immer weglassen,> ohne dass sich was ändert. Ist bei Anderas' Beispiel aber nicht der> Fall.
Aber es ändert sich doch tatsächlich nichts, wenn man das "extern"
weglässt: Der Compiler liefert immer noch die gleiche Fehlermeldung.
Er stört sich ja nicht an dem "extern", sondern daran, dass die Funktion
einmal ohne und einmal mit "static" deklariert ist.
Sina Anargo schrieb:> ich wollte "extern" richtig verstehen. Ursprünglich habe ich das von dem> folgenden wie ich finde sehr schönen Trick:
Der Trick ist Schwachsinn. Es reicht die Funktion einfach als inline zu
deklarieren. Funktionen sind sowieso extern, außer static Funktionen.
Der Hauptsinn von inline ist meiner Meinung nach auch nicht den Compiler
dazu zu bringen die Funktion zu inlinen, sondern erlaubt es Funktionen
in Headern zu deklarieren UND zu definieren, ohne das es beim Linken
Fehler wegen mehrfacher Definitionen gibt.
Yalu X. schrieb:> Er stört sich ja nicht an dem "extern", sondern daran, dass die Funktion> einmal ohne und einmal mit "static" deklariert ist.
Oh, wie peinlich... :-(((((
Johann L. schrieb:> ...was aber zeigt, dass eine extern-Deklaration eben nicht immer> überflüssig ist.
Das schrob ich ja auch nicht. Nur das Schlüsselwort "extern" ist
eben bei einer Funktionsdeklaration überflüssig (vom von A. K.
genannten, C99-spezifischen inline-Fall abgesehen).
Da in C allerdings eine Definition zugleich Deklaration ist, braucht
man eine Funktionsdeklaration (egal ob [implizit oder nicht] "extern"
oder "static") allerdings ohnehin nur dann, wenn sich zwei Funktionen
gegenseitig aufrufen können sollen, sodass es einer forward
Deklaration für eine von beiden bedarf.
Bronco schrieb:> Jetzt muß ich aber mal ganz dumm fragen:> Wann braucht man denn dann "extern" wirklich zwingendermaßen?
Wenn man eine Variable aus einer anderen Übersetzungseinheit meint. Ohne
"extern" könnte man sie andernfalls nämlich versehentlich definieren.
Auch:
A. K. schrieb:> Das bezog sich auf den Fall:> file1: int variable;> file2: int variable = 1;> Das in file1 ist nur dann eine Definition, wenn file2 fehlt. Mit file2> ist es eine Deklaration.
Du solltest näher beschreiben, wo file2 fehlt: In der
Übersetzungseinheit (#include "file2") oder beim Linken.
In file1 rutscht die variable nämlich nach .bss, in file2 wird sie eher
in .data angelegt. Das dürfte beim Linken recht unübersichtlich werden.
Bronco schrieb:> Jetzt muß ich aber mal ganz dumm fragen:> Wann braucht man denn dann "extern" wirklich zwingendermaßen?
Man braucht es für globale Variablen, die in einer anderen
Übersetzungseinheit definiert sind.
Zum Beispiel gibt es unter Linux die Umgebungsvariable environ. Wenn man
die in einem eigenen Programm verwenden will, so deklariert man:
Nase schrieb:> Bronco schrieb:>> Jetzt muß ich aber mal ganz dumm fragen:>> Wann braucht man denn dann "extern" wirklich zwingendermaßen?> Wenn man eine Variable aus einer anderen Übersetzungseinheit meint. Ohne> "extern" könnte man sie andernfalls nämlich versehentlich definieren.
Ohne "extern" könnte es nicht nur eine Definition sein, sondern ist
definitiv ("no pun intended") eine.
Hier ist der Unterschied zwischen Variablen und Funktionen. Bei der
Funktion ist klar, daß es ohne den Rumpf eine Deklaration sein muss. Bei
der Variablen gibt den nicht, also braucht man da etwas, womit man das
explizit markieren kann.
gcc ist es völlig gleichgültig, ob man das extern bei globalen Variablen
hinschreibt oder nicht. Der Linker zieht globale Variablen zusammen (so
daß sie nur einmal existieren) und meckert nur dann, wenn sie mehrfach
initialisiert werden (solange man nicht "-fno-common" vorgibt).
Aber auch wenn's der Compiler vielleicht nicht braucht: man selbst
wird's brauchen, früher oder später...
Markus F. schrieb:> Der Linker zieht globale Variablen zusammen
Habs oft genug beim gcc gehabt, dass er sich eine aussucht und nur einen
Teil dorthin verlinkt. Böser Fehler.
Manchmal finde ich, dass der gcc zu tolerant ist und selbst meint, was
richtig sein könnte. So einige Optionen sollten per default aktiv sein
und zu einem Error statt zu einer Warnung führen. Doch das its eine
andere Baustelle.
Markus F. schrieb:> gcc ist es völlig gleichgültig, ob man das extern bei globalen Variablen> hinschreibt oder nicht.
Wenn du bei einer wirklich extern deklarierten Variablen ohne 'extern'
keine 'error: redefinition of ...'-Meldung bekommst, hast du was falsch
gemacht!
Ralf G. schrieb:> Wenn du bei einer wirklich extern deklarierten Variablen ohne 'extern'> keine 'error: redefinition of ...'-Meldung bekommst, hast du was falsch> gemacht!
Probier's aus.
Markus F. schrieb:> gcc ist es völlig gleichgültig, ob man das extern bei globalen Variablen> hinschreibt oder nicht.
Nur bei bss-Variablen.
Bei data-Variablen (initialisierte Daten) natürlich nicht.
Ralf G. schrieb:> Wenn du bei einer wirklich extern deklarierten Variablen ohne 'extern'> keine 'error: redefinition of ...'-Meldung bekommst, hast du was falsch> gemacht!
Nö. Lies' dir das C99 Rationale, Abschnitt 6.2.2 “Linkage of
Identifiers” durch.
Hmm, das ist bei mir hintenruntergefallen...
Ich bevorzuge diese Variante:
Jörg Wunsch schrieb:> Aber:
Da wundert man sich dann auch nicht, falls mal ausversehen gleiche
Variablennamen verwendet werden, dass nichts mehr funktioniert.
(Bei meinem Test heute früh hatte ich g++ eingestellt. Deswegen die
abweichende Fehlermeldung.)
Jörg Wunsch schrieb:> Das sind die beiden verschiedenen Linkage-Modelle, die im Rationale> erwähnt sind. Hast du es dir denn mal angeguckt?
Ich bezieh mich auf
http://www.open-std.org/jtc1/sc22/wg14/www/C99RationaleV5.10.pdf
Dort ist zwar das Verhalten des gcc aufgeführt und fällt dort unter
"Relaxed Ref/Def". Es wird alledings auch gesagt, dass das eine COmmon
Extension ist die auf Unix-Linkern anzutreffen ist. Allerdings wäre das
'not strictly conforming"
Weiters heisst es weiter unten
1
The Standard model is a combination of features of the strict ref/def
2
model and the initialization model. As in the strict ref/def model, only
3
a single translation unit contains the definition of a given object
woraus ich schliesse, dass die Duldung des gcc-Linkers von mehreren
Definitionen nicht mehr als eben eine 'common extension" ist.
Karl Heinz schrieb:> Allerdings wäre das 'not strictly conforming"
Richtig: ein Programm, welches sich auf diese Variante verlässt, ist
"not strictly conforming", denn ein andere Compiler/Linker könnte ja
ein anderes Modell benutzen, auf dem das dann nicht mehr linkbar ist.
Aus heutiger Sicht wäre es auf jeden Fall schlechter Stil, sich auf
sowas zu verlassen.
Jörg Wunsch schrieb:> Aus heutiger Sicht wäre es auf jeden Fall schlechter Stil, sich auf> sowas zu verlassen.
Seh ich auch so.
Zumal es in der Praxis kein Problem ist, die One Definition Rule
durchzuziehen.
Ralf G. schrieb:> falls mal ausversehen gleiche> Variablennamen verwendet werden, dass nichts mehr funktioniert.
Und jetzt dämmert's bei mir wieder...
Genau das hatte ich mal gemacht (und das 'static' vergessen).
Danach habe ich mich durch die ganzen Optimierungs- und
Warneinstellungen durchgekämpft und erweitere jetzt als erstes immer die
Liste der Compiler-/ Linkerschalter in einem neuen Projekt.
(Was ja leider nicht aus einer Voreinstellungsdatei gelesen werden
kann.)
Ich empfehle folgende Vorgehensweise für Variablen/Funktionen, die
öffentlich gemacht werden:
1.) In *.c / *.cpp Files prinzipiell kein "extern" Schlüsselwort nutzen,
sowohl für Funktionen als auch Variablen. (Kann man wunderbar mit einem
grep Aufruf prüfen)
1
// Modul1.c
2
intTemperature;
3
voidMeasure(){<code>}
2.) In der Headerdatei, die die Schnittstelle zum Modul bildet, die
Deklarationen dann mittels "extern".
Klose schrieb:> extern void Measure();
Nur (und das war das Thema des Threads), dass das „extern“ in diesem
Falle weiter nichts ist als ein netter Kommentar. „void Measure();“
drückt genau dasselbe aus, und ist in C noch dazu etwas anderes als
„void Measure(void);“, was man hier besser geschrieben hätte.