Forum: Compiler & IDEs C Schlüsselwort extern


von Micha (Gast)


Lesenswert?

manchmal bin ich wirklich vergesslich, leichte Tendenz zu Alzheimer ;-(

aber gottseidank gibt es mikrocontroller.net und dessen Suchfunktion. 
Die Sache über die ich heute wieder mal beim praktischen Programmieren 
gestolpert war, war die Verwendung des C Schlüsselworts "extern".

Hab hier eine gute Erläuterung von Karl-Heinz Buchegger zu dem Thema 
gefunden, allerdings nicht unbedingt kurz gefasst. Vielleicht muss man 
manche Dinge manchmal auch ausführlich erklären.

Wollte nur mal fragen, ob meine Kurzfassung von dem was ich glaube 
verstanden zu haben, korrekt ist:

"extern" ist dafür da, um im Zweifelsfall eine Deklaration eindeutig als 
solche zu kennzeichnen und von einer Definition zu unterscheiden. Also 
mit extern stellt man sicher, dem Compiler nur zu sagen dass es die 
Variable oder Funktion irgendwo im Projekt gibt. Nicht mehr und nicht 
weniger.

Der Punkt der mir nicht klar ist: wenn etwas in einer Header-Datei 
steht, ist es dann per se eine Deklaration - also kann man das "extern" 
in header Dateien getrost immer weg lassen?

von Rolf Magnus (Gast)


Lesenswert?

Micha schrieb:
> Also mit extern stellt man sicher, dem Compiler nur zu sagen dass es die
> Variable oder Funktion irgendwo im Projekt gibt. Nicht mehr und nicht
> weniger.

Korrekt.

> Der Punkt der mir nicht klar ist: wenn etwas in einer Header-Datei
> steht, ist es dann per se eine Deklaration - also kann man das "extern"
> in header Dateien getrost immer weg lassen?

Header-Dateien werden in keiner Weise vom Compiler speziell behandelt. 
Wenn in einem File ein #include "header.h" steht, dann wird vom 
Präprozessor nichts weiter gemacht, als dieses include-Statement durch 
den im Header enthaltenen Code zu ersetzen.
Also verhält sich "extern" in einem Header exakt genauso, wie es sich 
verhalten würde, wenn es in jedem c-File stünde, das diesen Header 
einbindet.

von Micha (Gast)


Lesenswert?

Danke! Das war genau das Stück Gewissheit das mir noch gefehlt hat! Die 
Erklärung macht Sinn.

von TriHexagon (Gast)


Lesenswert?

Am besten schaust du dir den Prozess Quelldatei -> ausführbare Datei an, 
vor allem was der Linker da macht. Mit extern machst du dem Compiler 
klar, dass sich die Variable in einer anderen Quellcodedatei befindet. 
Dann ist es nämlich die Aufgabe des Linkers nach dem Kompilieren die 
Adresse der Variable einzutragen.

von TriHexagon (Gast)


Lesenswert?

Oh mir fällt gerade auf, dass das nicht ganz stimmt, denn der Linker 
muss das immer machen auch ohne "extern".

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

TriHexagon schrieb:
> Oh mir fällt gerade auf, dass das nicht ganz stimmt, denn der Linker
> muss das immer machen auch ohne "extern".

Nein, bei Objekten, die innerhalb der gleichen Übersetzungseinheit 
definiert sind, macht das der Compiler; bei Funktionen oder Variablen, 
die als "static" deklariert sind, gibt es sogar kein korrespondierendes 
Symbol in der Symboltabelle, das der Linker auflösen könnte.

von TriHexagon (Gast)


Lesenswert?

Ach so, dann werden die globalen Variablen gar nicht immer zentral an 
einer Stelle angelegt. Wieder was gelernt.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

TriHexagon schrieb:
> Ach so, dann werden die globalen Variablen gar nicht immer zentral an
> einer Stelle angelegt.

Was hat das mit meiner Aussage zu tun?

von Stefan E. (sternst)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Nein, bei Objekten, die innerhalb der gleichen Übersetzungseinheit
> definiert sind, macht das der Compiler;

Nö, wie sollte das denn funktionieren?

Rufus Τ. Firefly schrieb:
> bei Funktionen oder Variablen,
> die als "static" deklariert sind, gibt es sogar kein korrespondierendes
> Symbol in der Symboltabelle, das der Linker auflösen könnte

Doch, gibt es. Eine Ausnahme sind allenfalls Funktionen, die mit einem 
relativen call erreicht werden können.

von Rolf Magnus (Gast)


Lesenswert?

Stefan Ernst schrieb:
> Rufus Τ. Firefly schrieb:
>> Nein, bei Objekten, die innerhalb der gleichen Übersetzungseinheit
>> definiert sind, macht das der Compiler;
>
> Nö, wie sollte das denn funktionieren?

Wie sollte es denn sonst funktionieren?

> Rufus Τ. Firefly schrieb:
>> bei Funktionen oder Variablen,
>> die als "static" deklariert sind, gibt es sogar kein korrespondierendes
>> Symbol in der Symboltabelle, das der Linker auflösen könnte
>
> Doch, gibt es.

Nein. Wozu auch? static bedeutet, daß der Name in anderen 
Übersetzungseinheiten nicht bekannt sein soll, und das geht am 
einfachsten, indem man kein Linkersymbol dafür generiert.

> Eine Ausnahme sind allenfalls Funktionen, die mit einem relativen call
> erreicht werden können.

Was sollte das denn für einen Unterschied machen?

von Stefan E. (sternst)


Lesenswert?

Rolf Magnus schrieb:
> Stefan Ernst schrieb:
>> Rufus Τ. Firefly schrieb:
>>> Nein, bei Objekten, die innerhalb der gleichen Übersetzungseinheit
>>> definiert sind, macht das der Compiler;
>>
>> Nö, wie sollte das denn funktionieren?
>
> Wie sollte es denn sonst funktionieren?

Dir ist schon klar, dass es darum geht, wer die Adressen vergibt, oder? 
Das macht der Linker, nicht der Compiler.

Rolf Magnus schrieb:
>> Rufus Τ. Firefly schrieb:
>>> bei Funktionen oder Variablen,
>>> die als "static" deklariert sind, gibt es sogar kein korrespondierendes
>>> Symbol in der Symboltabelle, das der Linker auflösen könnte
>>
>> Doch, gibt es.
>
> Nein. Wozu auch?

Wozu? Damit der Linker für das Symbol eine Adresse vergeben und bei 
allen Referenzen innerhalb des Moduls eintragen kann.

Rolf Magnus schrieb:
> static bedeutet, daß der Name in anderen
> Übersetzungseinheiten nicht bekannt sein soll

Und? Was meinst du, warum es auch bei Linker-Symbolen eine 
Unterscheidung zwischen lokal und global gibt? Diese Symbole werden 
einfach direkt nach abarbeiten des aktuellen Moduls verworfen.

Rolf Magnus schrieb:
>> Eine Ausnahme sind allenfalls Funktionen, die mit einem relativen call
>> erreicht werden können.
>
> Was sollte das denn für einen Unterschied machen?

Das ist der einzige Fall, wo der Compiler bei statischen Objekten 
komplett ohne Mithilfe des Linkers auskommen kann.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Natürlich muß der Linker/Lokator auch statischen Variablen Speicher 
zuordnen.  Der Compiler kann das nicht machen — es gibt eben noch keine 
spukhafte Fernwirkung zwischen C-Modulen, die dem COmpiler z.B. sagen 
könnte, daß ein anderes Modul die Adresse 0x12345678 bereits für eine 
(statische) Variable verwendet.

Das einzige, was der Compiler machen kann, ist bestimmte variablen 
wegzuoptimieren, etwa
1
static const int i = 3;
Dafür braucht i.d.R. kein Speicher angelegt zu werden.  Ein Fall, wo 
Speicher dafür gebraucht wird, ist wenn die Adresse von i das Modul 
verlässt.

: Bearbeitet durch User
von TriHexagon (Gast)


Lesenswert?

Ok gut dann werden die Adressen doch hauptsächlich vom Linker vergeben. 
Bei meinem zweiten Beitrag sind mir die Linkerscripts und die .data/.bss 
Sections wieder eingefallen. Daraus schloss ich, dass Variablen ob 
initialisiert oder nicht initialisiert in einem gemeinsamen 
Speicherbereich angelegt werden und dass kann dann eigentlich nur der 
Linker (die letzte Instanz). Der Kompiler schaut sich ja nur jede 
Quellcodedatei einzeln an, nicht aber alle gemeinsam.

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.