Hallo,
wenn ich in zwei verschiedenen c-files eine statisch volatile variable
mit dem selben namen habe
file_1.c
1
staticvolatileuint8_tbreak=0;
file_2.c
1
staticvolatileuint8_tbreak=0;
kommen die sich in die quere? Nein, da diese statisch sind und nur für
die Datei gelten? volatile sagt ja, dass es von außen zugegriffen werden
kann.
Wie wäre es, wenn ich das static weglassen würde
marcel schrieb:> volatile sagt ja, dass es von außen zugegriffen werden> kann.
Sicher? Ich kenne volatile nur so, das dies für die Variable bedeutet,
dass diese zur Weiterverarbeitung immer aktualisiert werden muss und
nicht der zuletzt bekannte Wert genutzt werden darf. Sonst verpasst man
z.B. die Änderung, welche in einem Interrupt durchgeführt wurde.
Hast du die Variablen innerhalb einer Funktion oder global für die ganze
c-File definiert? Das macht nämlich einen Unterschied bei static!
Hallo,
static macht ja nur innerhalb einer Prozedur / Funktion sinn!
(nicht als globale Variable, da sie da automatisch "static" ist)
Innerhalb definiert sind die Variablen aber lokal und lokale Variable
machen globale Variable mit gleichem Namen unsichtbar.
marcel schrieb:> wenn ich in zwei verschiedenen c-files eine statisch volatile variable> mit dem selben namen habe
...
> kommen die sich in die quere?
Nein. Static ausserhalb einer Funktion ist "file scope", d.h. nur im
jeweiligen C-File bekannt.
Elektrolurch schrieb:> static macht ja nur innerhalb einer Prozedur / Funktion sinn!> (nicht als globale Variable, da sie da automatisch "static" ist)
Es gibt zwei Aspekte:
- wo der Name bekannt ist (scope),
- wo die Variable liegt (storage class).
Ein "static" ausserhalb einer Funktion beeinflusst nur wo man sie kennt,
innerhalb einer Funktion nur wo sie liegt. So hat man anno dunnemal ein
Keyword eingespart und seither Leute verwirrt.
marcel schrieb:> Wie wäre es, wenn ich das static weglassen würde
Wenn Du das static weg lässt, dann macht der Linker daraus eine
Variable. Könnte eine Warning generieren (doppelter Identifier).
Mit dem Static ist es eine Variable pro Quellen Datei, der Linker
allokiert also unterschiedliche Adressen. Kann man ausprobieren indem
man sich z.B. via Debugger die Adresse anzeigen lässt.
Mit "volatile" kennzeichnet man den Zugriff "von außern" aber mit
"static" ist der Name nur in der konkreten Quelldatei bekannt. Und ja,
auch die Kombination ist sinnvoll, z.B. wenn Interrupts oder DMA im
Spiel sind.
Elektrolurch schrieb:> static macht ja nur innerhalb einer Prozedur / Funktion sinn!> (nicht als globale Variable, da sie da automatisch "static" ist)
Wenn man keine Ahnung hat... </Nuhrzitat>
marcel schrieb:> volatile sagt ja, dass es von außen zugegriffen werden> kann.
Wobei "von aussen" in diesem Zusammenhang meint, dass es Zugriffe darauf
geben kann, von denen der Compiler nicht weiss. Mit der Sichtbarkeit des
Namens der Variable und der Platzallokation hat das nichts zu tun.
Anmerkung: Glaubt du es ist ein Zeichen von Klugheit eine Variable
zu verwenden die "break" heisst?
Wundert mich das dein Compiler dir da noch nicht auf die Finger
gehauen hat.
Olaf
Christian W. schrieb:> Sicher? Ich kenne volatile nur so, das dies für die Variable bedeutet,> dass diese zur Weiterverarbeitung immer aktualisiert werden muss und> nicht der zuletzt bekannte Wert genutzt werden darf. Sonst verpasst man> z.B. die Änderung, welche in einem Interrupt durchgeführt wurde.
Ja, da habe ich mich schlecht (sehr schlecht) ausgedrückt.
Das meinte ich aber. Also von Aussen in einem Interrupt.
Christian W. schrieb:> Hast du die Variablen innerhalb einer Funktion oder global für die ganze> c-File definiert? Das macht nämlich einen Unterschied bei static!
die ist für die c-file.
Hintergrund ist der, dann kann ich in der c-file irgendwo break
reinschreiben und habe dort zum debuggen definitiv einen Breakpoint
welcher nicht wegoptimiert wird.
Olaf schrieb:> Anmerkung: Glaubt du es ist ein Zeichen von Klugheit eine Variable> zu verwenden die "break" heisst?
ja, wenn man für 5 zeichen schon zu faul ist :/
break würde/wird wahrscheinlich nicht gehen.
nenne diese auch immer breakpoint.
Grund ist, dass ich diese als breakpoint verwende
z.B.
1
......
2
if(a!=2)
3
{
4
breakpoint++;
5
}
6
......
dort kann ich dann sicher sein, dass dieser nicht wegoptimiert wird, und
so beim debuggen ein stop setzen kann wenn eine bestimmte bedingung
eingetreten ist.
marcel schrieb:> static volatile uint8_t break = 0;
Wozu?
Das sind im Grunde zwei Dinge:
1. Vereinbaren von Speicherplatz für die Variable
2. Befüllen der Variablen mit einem Wert.
Also im Grunde so:
char break;
und dann in der zugehörigen Funktion irgendwo
break = 0;
Und das ganze Gehampel nur deshalb, weil man gelegentlich in Funktionen
auch Variablen braucht, die persistent sind und deshalb nicht auf dem
Stack sondern ohne Stack direkt irgendwo im RAM angeordnet sind. Aber
zugleich will man aus Ideologie-Gründen normale Variablen direkt im RAM
vermeiden, genauso wie man Marke und goto vermeiden will und deshalb
Anweisungen verwendet, die eigentlich für was anderes gedacht sind.
Und ja, der Linker meckert bei sowas gewiß, denn jede 'static' Variable
kommt direkt in den RAM und nicht per Stackpointer irgendwo hin je nach
Programmablauf und so hat der Linker es mit zwei namensgleichen
Variablen zu tun, wenn nicht zuvor der Compiler oder Assembler da etwas
dran herum macht. Das ist eben so, weil C kein Modulsystem kennt und die
gegenseitige Bekanntgabe von Namen entweder mit vorgestelltem 'extern'
oder durch Einbindung von Headerdateien erfolgt. Also völlig ungeregelt.
Wenn man das als Programmierer beherzigt und geeignete Namen verwendet,
die von sich aus nicht mit anderen Namen kollidieren, dann kann man sich
auch solche Krücken wie 'static' ersparen.
Und nochwas: Namen, die Schlüsselwörtern entsprechen, sollte man lieber
vermeiden. Nenne deine Variable lieber ottokar oder mybreak. Oder stelle
deine Programmierweise um, so daß du so etwas garnicht benötigst.
W.S.
W.S. schrieb:> Anweisungen verwendet, die eigentlich für was anderes gedacht sind.
Übersetze static einfach mit "stationär". Dann erschließt es sich: Die
Variable ist hier stationär.
> gegenseitige Bekanntgabe von Namen entweder mit vorgestelltem 'extern'> oder durch Einbindung von Headerdateien erfolgt. Also völlig ungeregelt.
Nicht ODER.
Header-Dateien bieten die Möglichkeit, Codezeilen in mehrere Files
einzubinden.
extern macht z.B. Variablen bekannt. Geregelt ist das sehr genau. Du
bist nur nicht zu obskuren Anordnungen gezwungen.
> Wenn man das als Programmierer beherzigt und geeignete Namen verwendet,> die von sich aus nicht mit anderen Namen kollidieren, dann kann man sich> auch solche Krücken wie 'static' ersparen.
Das fördert aber nicht immer die Lesbarkeit. While ist nicht deshalb
nutzlos, weil ich es durch for ersetzen könnte.
Christian W. schrieb:> Sicher? Ich kenne volatile nur so, das dies für die Variable bedeutet,> dass diese zur Weiterverarbeitung immer aktualisiert werden muss und> nicht der zuletzt bekannte Wert genutzt werden darf. Sonst verpasst man> z.B. die Änderung, welche in einem Interrupt durchgeführt wurde.
Nicht ganz. volatile sagt dem Compiler nur, dass er sie nicht optimieren
darf. Hintergrund dazu ist, dass sich die Variable ändern kann ohne dass
dies der Compiler erkennt. Dein Beispiel mit dem Interrupt ist so eine
Sache: Wird eine Variable nur im Interrupt geändert und in der Main-Loop
wird lediglich darauf nur zugegriffen kann sie dem Compiler als
Konstante erscheinen und er optimiert ggf. Vergleiche und ähnliches mit
ihr einfach weg.
Theoretisch geht es 2 gleiche Variablen dateistatisch
in verschiedenen c- Dateien zu haben.
Praktich ist es aber kacke 2 gleiche Variablen auf den selben
Port verweisen zu lassen, wenn ichs hier richtig verstanden hab.
Denn...
Woher sollen die Routinen in den getrennten C- Dateien wissen,
wer gerad auf den Port zugreift?
Da dürfte es dann Wettrenn-Erscheinungen kommen, die dann Dein Proggy
blockieren---
Fazit:
Bei mir dürfte nur die Routinen einer C-Datei auf den Port zugreifen.
mfg
static volatile kann man schreiben, wenn der Interrupthandler und die
Mainfunktion im selben C-File sind.
marcel schrieb:> Wie wäre es, wenn ich das static weglassen würde
Dann werden sie vom GCC auf die selbe Adresse gelinkt.
Bei anderen Compilern muß das aber nicht sein, daher gibt es eine
Warnung.
Die saubere Lösung ist daher, sie nur in einem C-File zu definieren und
in alle anderen eine Deklaration zu includieren.
Peter D. schrieb:> marcel schrieb:>> Wie wäre es, wenn ich das static weglassen würde>> Dann werden sie vom GCC auf die selbe Adresse gelinkt.
Nein. Es gibt einen Fehler wegen Verletzung der ODR.
Wilhelm M. schrieb:> Peter D. schrieb:>> marcel schrieb:>>> Wie wäre es, wenn ich das static weglassen würde>>>> Dann werden sie vom GCC auf die selbe Adresse gelinkt.>> Nein. Es gibt einen Fehler wegen Verletzung der ODR.
Aber erst seit gcc 10. Frühere Versionen hatten -fcommon als default,
das das von Peter genannte Verhalten zeigt.
Und wie immer: C++ ist nicht C.
Oliver
Jim M. schrieb:> marcel schrieb:>> Wie wäre es, wenn ich das static weglassen würde>> Wenn Du das static weg lässt, dann macht der Linker daraus eine> Variable. Könnte eine Warning generieren (doppelter Identifier).Wilhelm M. schrieb:>> Dann werden sie vom GCC auf die selbe Adresse gelinkt.>> Nein. Es gibt einen Fehler wegen Verletzung der ODR.
Denn ist das ja eindeutig geklärt...
Oliver S. schrieb:> Wilhelm M. schrieb:>> Peter D. schrieb:>>> marcel schrieb:>>>> Wie wäre es, wenn ich das static weglassen würde>>>>>> Dann werden sie vom GCC auf die selbe Adresse gelinkt.>>>> Nein. Es gibt einen Fehler wegen Verletzung der ODR.>> Aber erst seit gcc 10. Frühere Versionen hatten -fcommon als default,> das das von Peter genannte Verhalten zeigt.
C kennt die sogenannten "tentative definitions" (dürfen keine
initializer haben). Nur diese können mit -fcommon zusammengefasst
werden. Dies trifft aber für das obige Beispiel nicht zu. Dort sind es
wegen des Initializers "echte" Definitionen mit external linkage, was
zur Verletzung der ODR führt.
A. S. schrieb:> Übersetze static einfach mit "stationär". Dann erschließt es sich: Die> Variable ist hier stationär.
Man hätte auch 'typedef' anders benennen können, aber das Grundproblem
ist, daß hier versucht wird, irgendwelche Variablen, die eigentlich in
eine Deklaration außerhalb von Funktionen gehören, so zu deklarieren,
daß keiner außerhalb eben der betreffenden Funktion drauf zugreifen
kann.
Wozu?
Eigentlich nur, um Leute zu disziplinieren, die sich partout daneben
benehmen wollen und ihre Finger nicht von Innereien anderer Funktionen
weglassen können.
OK, es hat auch mit dem fehlenden Modulsystem bei C zu tun. Wenn man
nicht die Möglichkeit hat, die Namen von Variablen und Funktionen
dediziert zu exportieren oder ebenso dediziert es eben nicht zu tun,
dann landet man schlußendlich bei solchen Verrenkungen. Hier haben wir
ja einen, der zwei namensgleiche Variablen in zwei verschiedenen Modulen
hinschreiben will und dann noch fragt, ob das eventuell ein Problem
geben könnte.
Peter D. schrieb:> Dann werden sie vom GCC auf die selbe Adresse gelinkt.> Bei anderen Compilern muß das aber nicht sein,...
Du bist mal wieder sehr auf den GCC orientiert. Nun, es gibt nicht nur
andere C-Compiler, sondern sogar noch andere Programmiersprachen, wo so
etwas ganz anders geregelt ist.
A. S. schrieb:> extern macht z.B. Variablen bekannt. Geregelt ist das sehr genau. Du> bist nur nicht zu obskuren Anordnungen gezwungen.
Also, man kann zwecks Bekanntmachung von Namen:
1. eine Datei - gemeinhin Headerdatei genannt - inkludieren, wo dann die
Bezeichnungen drinstehen. Jede andere Text-Datei würde das auch tun,
vorausgesetzt, dort steht das Richtige drin.
2. einfach ein 'extern' vor eine Deklaration schreiben. Ohne irgend eine
inkludierte Datei. Man sollte so etwas besser nicht tun, aber es geht
und widerspricht nicht der Sprachdefinition.
Und was obskure Anweisungen betrifft, erachte ich ein
for(;;) {...}
oder ein
while(true) {...}
als obskur. Denn sowohl for als auch while wurden eigentlich für
abgezählte oder bedingte Schleifen erfunden - aber nicht für
bedingungslose.
W.S.
> 1. eine Datei - gemeinhin Headerdatei genannt - inkludieren, wo dann die
Ich hab in meinen headerdateien immer sowas
#ifdef MAIN
uint8_t dumdidum;
#else
extern uint8_t dumdidum;
#endif
und in main.c:
#define MAIN
#include ...
Dann gibt es jede Variable nur einmal. Und das natuerlich nur in
begruendeten Ausnahmefaellen und niemals heissen die wie
Schluesselworte. .-)
Olaf
Olaf schrieb:> Ich hab in meinen headerdateien immer sowas
Warum?
Wenn Du doch beides schreiben musst und noch was zusätzlich, ist es doch
mehr Arbeit und weniger lesbar.
Wenn, dann extern wegzaubern. Ist auch blöd, aber nur eine Stelle.
Und geprüft wird bei Dir nicht (ganz böse)
Olaf schrieb:> #ifdef MAIN> uint8_t dumdidum;> #else> extern uint8_t dumdidum;> #endif
Das geht auch so, dass man die Variablen nur einmal hinschreiben muss:
1
#ifdef MAIN
2
#define EXT
3
#define E_INIT(x) = (x)
4
#else
5
#define EXT extern
6
#define E_INIT(x)
7
#endif
8
9
EXT int foo E_INIT(42);
10
EXT char * bar E_INIT("Alle meine Entchen");
11
...
Das ist aber Geschmackssache. Früher habe ich solche Konstrukte genutzt,
später eher darauf verzichtet.
Olaf schrieb:>> 1. eine Datei - gemeinhin Headerdatei genannt - inkludieren, wo dann die>> Ich hab in meinen headerdateien immer sowas>> #ifdef MAIN> uint8_t dumdidum;> #else> extern uint8_t dumdidum;> #endif>> und in main.c:>> #define MAIN>> #include ...
Das sind so typische Sachen, die Hobby- oder Heldenprogrammierer machen:
sie denken, es sei cool, wenig hinzuschreiben bzw. das Leben für den
Ersteller (sich selbst) einfach zu machen. Im echten Leben schreibt man
Code aber für andere Leute, die nicht überrascht werden wollen, wenn sie
ein Artefakt anschauen. Und hier wird man überrascht, weil in der
Headerdatei nun zu den Deklarationen auch noch die Definitionen stehen,
die vermutlich in einer ganz anderen Implementierungsdatei stehen
sollten.
Wilhelm M. schrieb:> Und hier wird man überrascht, weil in der Headerdatei nun zu den> Deklarationen auch noch die Definitionen stehen, die vermutlich in einer> ganz anderen Implementierungsdatei stehen sollten.
Eben, genau deshalb mache ich das wie oben beschrieben schon lange nicht
mehr, diese Vermengung von Definition und Deklaration ist wirklich nicht
sauber. Das verhindert auch die Wiederverwendbarkeit von Source-Modulen
in anderen Projekten, macht es zumindest schwerer, den Source weiter zu
verwenden.
Meiner Meinung gehört in eine Header-Datei lediglich das Interface rein.
Das kann unter bestimmten Umständen auch mal eine globale Variable als
externe Deklaration sein - aber mehr nicht.
Ich schrieb dazu auch:
Frank M. schrieb:> Das ist aber Geschmackssache. Früher habe ich solche Konstrukte genutzt,> später eher darauf verzichtet.
Ich hatte hier eher auf die technische Möglichkeit mittels Makros
hingewiesen, nicht, dass ich diesen "Makro-Trick" gut finde. Hier
scheinen aber einige nicht genau lesen zu können.
Frank M. schrieb:> Ich hatte hier eher auf die technische Möglichkeit mittels Makros> hingewiesen, nicht, dass ich diesen "Makro-Trick" gut finde. Hier> scheinen aber einige nicht genau lesen zu können.
Deswegen hatte ich Deinen Beitrag auch nicht zitiert.
Frank M. schrieb:> Das kann unter bestimmten Umständen auch mal eine globale Variable als> externe Deklaration sein - aber mehr nicht.
Wenn man die Variablen in einem Modul geordnet per .h den anderen
Programmteilen kundgeben will, dann schreibt man sie mit vorangestelltem
'extern' in die .h und ohne dieses in seine .c und man kann das ebenso
mit Funktionen tun. So etwas durchzuzuiehen, ist ein Beitrag zur
Lesbarkeit und auch zur Geradlinigkeit beim Programmieren, obwohl hier
in diesem Forum gar viele Leute laut aufkreischen, weil es bei
Funktionen nicht zwingend notwendig ist.
Also etwa so:
in der Emil.h
extern char Ottokar;
extern void Karlheinz (...Karlheizens Parameterliste);
und in der Emil.c
#include "Emil.h"
char Ottokar;
void Karlheinz (...Karlheizens Parameterliste)
{ Inhalt von Karlheinz
}
Das benötigt keinerlei #ifdef Gehampel und ist leserlich. Und wenn
Emil.h woanders inkludiert wird, ist dort sehr einfach zu ersehen, daß
Karlheinz keine Forward-Deklaration ist, die in derselben Datei steht,
sondern etwas Externes ist, das in Emil.c zu finden ist.
W.S.
>> Und was obskure Anweisungen betrifft, erachte ich ein> for(;;) {...}> oder ein> while(true) {...}> als obskur. Denn sowohl for als auch while wurden eigentlich für> abgezählte oder bedingte Schleifen erfunden - aber nicht für> bedingungslose.>> W.S.
Nur für Leute mit eingeschränktem Gesichtsfeld,
die die Bedingung „immer“ nicht kennen.
W.S. schrieb:> Wenn man die Variablen in einem Modul geordnet per .h den anderen> Programmteilen kundgeben will, dann schreibt man sie mit vorangestelltem> 'extern' in die .h und ohne dieses in seine .c [...]
Ach.
> und man kann das ebenso mit Funktionen tun.
Man sollte das ebenso mit Funktionen tun. Jeder halbwegs aktuelle
Compiler aus den letzten 10-20 Jahren schmeisst zumindest eine Warnung
raus, wenn man eine externe Funktion nicht vorher auch extern deklariert
hat:
1
$ cat foo.c
2
int main (void)
3
{
4
foo ();
5
return 0;
6
}
7
8
$ cc -c foo.c
9
foo.c: In function ‘main’:
10
foo.c:3:5: warning: implicit declaration of function ‘foo’ [-Wimplicit-function-declaration]
11
3 | foo ();
Wohlgemerkt: Hier wird nicht gelinkt, sondern nur compiliert.
Mit welchen steinalten Compilern arbeitest Du, dass Du das noch als
Kann-Option ansiehst? Ich erinnere mich zuletzt an UNIX-Compilern aus
den 80ern, die so etwas noch ohne Meckern durchließen.
Dass so etwas auch heute noch nur eine Warnung und keinen echten Fehler
ausgibt, ist der Abwärtskompatibilität zum Ur-C (Kernighan-Ritchie)
geschuldet. Aber das kann man leicht mit entsprechenden
Compiler-Switches korrigieren.
P.S.
Ich arbeite zumindest beim gcc mit den Optionen "-Wall -Wextra -Werror",
also:
- Aktiviere (fast) alle Warnungen
- Aktiviere weitere spezielle Warnungen
- Werte jede Warnung als Fehler und brich dabei die Compilierung ab
Frank M. schrieb:> Ich erinnere mich zuletzt an UNIX-Compilern aus> den 80ern, die so etwas noch ohne Meckern durchließen.
Vor dem Prototyping von ANSI-C war das quasi Sprachstandard, da in einer
Deklaration einzig der Return-Typ festgelegt wurde, nicht aber die
Parameter.
Wer was auf sich hielt, verwendete sowieso "lint" zur Kontrolle.
(prx) A. K. schrieb:> Vor dem Prototyping von ANSI-C war das quasi Sprachstandard, da in einer> Deklaration einzig der Return-Typ festgelegt wurde, nicht aber die> Parameter.
Ja, jedoch war schon der Return-Typ wichtig, wenn er nicht gerade "int"
war. Das förderte natürlich auch die Faulheit: Damals beschränkten sich
viele Programmierer darauf, nur die Funktionen, die nicht "int"
zurücklieferten, überhaupt extern zu deklarieren. Denn damals wurde vom
Compiler einfach alles, was nicht deklariert wurde, als "int" angesehen.
Macht der gcc natürlich auch heute noch, glücklicherweise aber seit
einigen Jahrzehnten mit einer entsprechenden Warnung.
> Wer was auf sich hielt, verwendete sowieso "lint" zur Kontrolle.
Ja, das war damals auch mein Werkzeug. Das hat sich dann jedoch mit
Einführung des Prototyping danach größtenteils erledigt.
Frank M. schrieb:> Man sollte das ebenso mit Funktionen tun.
Du hast ihn missverstanden. Die Deklaration einer globalen Funktion ist
unstrittig.
W.S. geht es meist um das Schlüsselwort extern davor. Das darf
entfallen und tut es auch meist. Nur wer die Hälfte seines
Programmierlebens mit PROCEDURE, BEGIN und END verbringt, besteht
darauf.
A. S. schrieb:> W.S. geht es meist um das Schlüsselwort extern davor. Das darf> entfallen und tut es auch meist. Nur wer die Hälfte seines> Programmierlebens mit PROCEDURE, BEGIN und END verbringt, besteht> darauf.
Ich hatte das vor Urzeiten im Compiler mal umgedreht, weil mir das
extern/static auf den Zeiger ging. Und ein Keyword "global" eingebaut,
mit dem Funktionen und Variablen external scope bekamen, sondern hatten
sie file scope. Dieses Verhalten war natürlich per Option wählbar.
A. S. schrieb:> W.S. geht es meist um das Schlüsselwort extern davor.
Also....
Diese Empfehlung, extern vor eine Funktionsdeklaration zu schreiben,
höre ich hier zum ersten mal.
In der Praxis ist mir das auch noch nie aufgefallen, dass das ein
anderer tut.
Ein Sinn, will mir nicht einleuchten......
EAF schrieb:> Ein Sinn, will mir nicht einleuchten......
Ist bei Funktionen unnötig, ergibt sich aber strukturell aus der
Bedeutung von "extern" für Variablen. Und bei denen ist es nötig. Wer
Sinn für solche Systematik hat, mag es nutzen.
EAF schrieb:> Ein Sinn, will mir nicht einleuchten......
Bei Funktionen hat die Deklaration keinen Körper, die Definition
natürlich schon.
Das geht bei Variablen nicht, deswegen extern, um die Deklaration von
der Definition zu unterscheiden.
Frank M. schrieb:>> und man kann das ebenso mit Funktionen tun.>> Man sollte das ebenso mit Funktionen tun. Jeder halbwegs aktuelle> Compiler aus den letzten 10-20 Jahren schmeisst zumindest eine Warnung> raus, wenn man eine externe Funktion nicht vorher auch extern deklariert> hat:...
Ähem... nö. Ich stimme dir zu, daß man das 'extern' auch vor die
Funktionen schreiben sollte, die man in einer .h kundtut. Eben aus
Gründen der Systematik und damit der Lesbarkeit. Aber mir ist noch nie
ein C-Compiler begegnet, der das Weglassen von 'extern' moniert hätte.
Man sollte das eigentlich einbauen.
W.S.
Wilhelm M. schrieb:> Das geht bei Variablen nicht, deswegen extern, um die Deklaration von> der Definition zu unterscheiden.
Doch, auch bei Variablen kann man das unterscheiden: mit und ohne
expliziter Initialisierung. Früher wurden Variablen ohne sie intern
routinemässig in Commons umgesetzt (vgl Fortan), weshalb sie beliebig
oft ohne extern definierbar waren. Kam keine explizit initialisierte
Definition hinzu, wurden alle solchen Commons gleichen Namens vom Linker
übereinandergelegt.
Es gab also 3 Stufen:
extern int unsinn; // Deklaration
int unsinn = 1; // Definition, nur 1x möglich
int unsinn; // sowohl Deklaration als auch ggf Definition
(prx) A. K. schrieb:> Wilhelm M. schrieb:>> Das geht bei Variablen nicht, deswegen extern, um die Deklaration von>> der Definition zu unterscheiden.>> Doch, auch bei Variablen kann man das unterscheiden: mit und ohne> expliziter Initialisierung.
Nicht ganz, hatte ich oben auch schon geschrieben. Was Du meinst, sind
"tentative definitions", d.h. eine Definition (ohne) extern wird
(stillschweigend) zu einer Deklaration und kann mit gleichen
Definitionen in anderen TUs zusammengefasst werden (was normalerweise
einen Fehler wegen Verletzung der ODR bedeuten würde). Dazu bedarf es
beim gcc dann noch -fcommon
Wilhelm M. schrieb:> Dazu bedarf es beim gcc dann noch -fcommon
Heute ja, damals war das üblich. Dieses Verhalten früher Compiler
erklärt, weshalb die Sprache so definiert ist. Der umständliche Zirkus
von genau 1x ohne extern, sonst mit extern, war damals auch bei vielen
Variablen unnötig.
(prx) A. K. schrieb:> Wilhelm M. schrieb:>> Dazu bedarf es beim gcc dann noch -fcommon>> Heute ja, damals war das üblich. Dieses Verhalten früher Compiler> erklärt, weshalb die Sprache so definiert ist. Der umständliche Zirkus> von genau 1x ohne extern, sonst mit extern, war damals auch bei vielen> Variablen unnötig.
Ich denke, der TO ist an einer heutigen Lösung interessiert ;-)
Wilhelm M. schrieb:> Ich denke, der TO ist an einer heutigen Lösung interessiert ;-)
Und ich an einer Erklärung, warum C stellenweise seltsam wirkt. ;-)
(prx) A. K. schrieb:> weshalb sie beliebig> oft ohne extern definierbar waren. Kam keine explizit initialisierte> Definition hinzu, wurden alle solchen Commons gleichen Namens vom Linker> übereinandergelegt.
Kann man sich noch heute mit static auf File-Scope anschauen :-)
EAF schrieb:> In der Praxis ist mir das auch noch nie aufgefallen, dass das ein> anderer tut.
Dann schau Dir seinen Code an. Er ist zwar (nach eigenen Angaben) kein
Experte oder Freund von C (eher Pascal), macht aber beeindruckende
Projekte.