Forum: Mikrocontroller und Digitale Elektronik in zwei c files volatile variablen mit selbem namen


von marcel (Gast)


Lesenswert?

Hallo,

wenn ich in zwei verschiedenen c-files eine statisch volatile variable 
mit dem selben namen habe
file_1.c
1
static volatile uint8_t break = 0;
file_2.c
1
static volatile uint8_t break = 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

von Christian W. (orikson)


Lesenswert?

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!

von Elektrolurch (Gast)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

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.

: Bearbeitet durch User
von Jim M. (turboj)


Lesenswert?

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>

von (prx) A. K. (prx)


Lesenswert?

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.

von Olaf (Gast)


Lesenswert?

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

von marcel (Gast)


Lesenswert?

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.

von marcel (Gast)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

Dann scheint es wenig sinnvoll, in jedem File eine eigene Version dieser 
Variablen mit möglicherweise unterschiedlichem Inhalt zu haben.

: Bearbeitet durch User
von W.S. (Gast)


Lesenswert?

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.

von A. S. (Gast)


Lesenswert?

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.

von M. K. (sylaina)


Lesenswert?

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.

von Lotta  . (mercedes)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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.

von Wilhelm M. (wimalopaan)


Lesenswert?

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.

von Oliver S. (oliverso)


Lesenswert?

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

von Kurt (Gast)


Lesenswert?

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...

von Wilhelm M. (wimalopaan)


Lesenswert?

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.

von W.S. (Gast)


Lesenswert?

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.

von Olaf (Gast)


Lesenswert?

> 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

von A. S. (Gast)


Lesenswert?

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)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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.

von Wilhelm M. (wimalopaan)


Lesenswert?

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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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.

: Bearbeitet durch Moderator
von Wilhelm M. (wimalopaan)


Lesenswert?

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.

von W.S. (Gast)


Lesenswert?

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.

von GCC (Gast)


Lesenswert?

>
> 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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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

: Bearbeitet durch Moderator
von (prx) A. K. (prx)


Lesenswert?

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.

: Bearbeitet durch User
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

(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.

: Bearbeitet durch Moderator
von A. S. (Gast)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

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.

von EAF (Gast)


Lesenswert?

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......

von (prx) A. K. (prx)


Lesenswert?

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.

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

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.

von W.S. (Gast)


Lesenswert?

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.

von Wilhelm M. (wimalopaan)


Lesenswert?

W.S. schrieb:
> Aber mir ist noch nie
> ein C-Compiler begegnet, der das Weglassen von 'extern' moniert hätte.

Wird auch keiner kommen, weil es schlicht lt. Standard so nicht 
gebraucht wird. Der Grund steht hier: 
Beitrag "Re: in zwei c files volatile variablen mit selbem namen"

von (prx) A. K. (prx)


Lesenswert?

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

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

(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

von (prx) A. K. (prx)


Lesenswert?

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.

von Wilhelm M. (wimalopaan)


Lesenswert?

(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 ;-)

von (prx) A. K. (prx)


Lesenswert?

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. ;-)

von A. S. (Gast)


Lesenswert?

(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 :-)
1
static int a;
2
...
3
static int a = 7;
4
...
5
static int a;
6
7
8
int dummy(voi)
9
{
10
   return a;
11
}

von A. S. (Gast)


Lesenswert?

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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.