Sch*** Alzheimer! Bin ganz sicher, ich wusste das schon mal.
Ich stöber gerade in einem C-Quelltext für einen Atmel herum. Da sind
einige Variablen, die ausserhalb von functions deklariert werden mittels
"static" vereinbart.
Bei lokalen Variablen, also innerhalb von functions, ist die Verwendung
von static trivial: die Variablen merken sich dann ihre Werte zwischen
verschiedenen Aufrufen der function.
Aber warum verwendet man static bei globalen Variablen? Ich finde gerade
in meinem Lieblings-Lehrbuch zu C keine Erklärung, und bei Tante Gugel
find ich auch nix auf die schnelle.
Micha schrieb:> Aber warum verwendet man static bei globalen Variablen? Ich finde gerade> in meinem Lieblings-Lehrbuch zu C keine Erklärung, und bei Tante Gugel> find ich auch nix auf die schnelle.
solche Variablen können nur in dieser C quelle verwendet werden. Sie
werden vom Compiler also nicht exportiert. Eventuell optimiert er sogar
besser.
Wenn ein Programm aus mehreren "translation units" zusammengesetzt wird,
also aus mehreren einzelnen einzeln übersetzten C-Quelltextdateien
besteht, die vom Linker zusammengefasst werden, dann wird für eine
statische globale Variable kein Linkersymbol generiert, was zur Folge
hat, daß über die Grenze einer "translation unit" hinweg nicht auf das
betreffende Symbol zugegriffen werden kann.
Damit sind statische globale Variablen außerhalb ihrer "translation
unit" unsichtbar. Es kann daher in einem Programm mehrfach eine Variable
gleichen Namens verwendet werden, ohne daß es zu Konflikten kommt.
Das bezieht sich übrigens nicht nur auf Variablen, sondern auch auf
Funktionen; eine als static deklarierte Funktion ist ebenfalls nur
innerhalb ihrer "translation unit" sichtbar.
Somit ist folgendes zulässig:
a.c
1
#include"a.h"
2
3
staticintbla=4;
4
5
staticintmachwas(void)
6
{
7
returnbla;
8
}
9
10
intmachwas_in_a(void)
11
{
12
returnmachwas();
13
}
b.c
1
#include"b.h"
2
3
staticintbla=5;
4
5
staticintmachwas(void)
6
{
7
returnbla;
8
}
9
10
intmachwas_in_b(void)
11
{
12
returnmachwas();
13
}
a.h
1
intmachwas_in_a(void);
b.h
1
intmachwas_in_b(void);
main.c
1
#include<stdio.h>
2
3
#include"a.h"
4
#include"b.h"
5
6
intmain(int,char**)
7
{
8
printf("A: %d\n",machwas_in_a());
9
printf("B: %d\n",machwas_in_b());
10
return0;
11
}
In diesem (zugegebenermaßen nur eingeschränkt sinnvollen Beispiel) gibt
es innerhalb eines Programmes zwei Variablen namens "bla" und zwei
Funktionen namens "machwas". Und trotzdem gibt es keine Linkerkonflikte.
Sinn vonnt janze ist es, Implementierungsdetails auf die "translation
unit" beschränken zu können.
In C++ ist so etwas dank namespaces etc. einfacher zu handhaben.
chris schrieb:> Im PC Bereich sowie GCC ja, ansonsten trifft man oft auf Systemen wo> dies> nicht zutrifft.
wie schon einmal gesagt, dann ist es kein C mehr. Da es hier im C geht,
werden globale variablen immer auf 0 gesetzt.
chris schrieb:> Habe extra in den Spezifikationen nachgesehen.> Seit C11 stimmt deine Aussage, aber von ANSI X3.159 bis incl C99> sieht es anders aus.
Quatsch. In C99 z.B. steht:
1
If an object that has static or thread storage duration is not initialized
2
explicitly, then:
3
— if it has pointer type, it is initialized to a null pointer;
4
— if it has arithmetic type, it is initialized to (positive or unsigned) zero;
5
— if it is an aggregate, every member is initialized (recursively) according to these rules,
6
and any padding is initialized to zero bits;
7
— if it is a union, the first named member is initialized (recursively) according to these
8
rules, and any padding is initialized to zero bits;
chris schrieb:> Seit C11 stimmt deine Aussage, aber von ANSI X3.159 bis incl C99> sieht es anders aus.
In sämtlichen C Versionen seit Ritchies ersten veröffentlichten Untaten
war das so.
Nicht auszuschliessen ist jedoch, dass es C Compiler für Mikrocontroller
gibt, die sich nicht konform verhalten.
static hat nicht nur Vorteile:
Im Mapfile stehen die die Variablen nicht, man sieht nur 'Lücken' im
Memorymap und kann nicht sagen welche Variable dort tatsächlich liegt.
Dazu muss man erst den Debugger starten und via ELF-File sich anzeigen
lassen (wenn sie dort drin stehen. Manche Compiler machen nicht mal
das).
Mein persönlichen Erfahrungen haben mich schon vor langem zu dem
Entschluss gebracht das static zu vermeiden wo es geht.
Zugriffsschutz kann man auch anders machen, auch in C (z.B. die lokalen
Variablen im Headerfile per #ifdef PRIVATE klammern).
Und mehrfache gleichnamige static Variablen sehe ich bestenfalls bei per
Codegenerator erstelltem Code als sinnvoll an.
Reinhold_E schrieb:> Im Mapfile stehen die die Variablen nicht, man sieht nur 'Lücken' im> Memorymap und kann nicht sagen welche Variable dort tatsächlich liegt.
ich muss sagen das mir das Mapfile eigentlich ziemlich egal ist. Die
größe meine static Variablen kann ich selber recht gut überblicken.
Das ist für mich kein Grund ohne static zu arbeiten.
Es gab folgende storage class:
typedef
extern
auto
register
static
intern
Nur die letzten zwei sind mit 0 zu initialisieren.
Dass globale Variablen der Klasse static und locale Variablen der Klasse
auto zugewiesen werden, wie man es vielleicht in der Schule gelernt hat,
mag stimmen.
Diese Konvention ist aber nicht im Standard enthalten und Compiler für
Architekturen, welche keinen Heap haben, verwenden auto für globale
Variablen. Wenn ein Heap vorhanden ist, ist auto automatisch der Heap
und
global ist dann intern oder static, bzw im Endeffekt static, da es
nicht
sinnvoll wäre globale Variablen im Heap zu speichern.
chris schrieb:> Es gab folgende storage class:> typedef> extern> auto> register> static> intern> Nur die letzten zwei sind mit 0 zu initialisieren.
Nein, du liest nicht richtig. In den Zitaten aus den Standards steht
nicht "static storage class", sondern "static storage duration". Und
jetzt lies dir in C99 den Abschnitt 6.2.4 durch. Globale Variablen sind
"static storage duration".
chris schrieb:> Diese Konvention ist aber nicht im Standard enthalten
Doch.
> Architekturen, welche keinen Heap haben, verwenden auto für globale> Variablen.
Nein. Falls du es umgekehrt meinst, also dass ohne adressierbaren Stack
lokale Variablen auch gerne mal statisch angelegt werden: Das ist eine
Konzession an effizienten Code bei 8051/PIC16, ist aber nicht vom
Strachstandard gedeckt, weil es Rekursion ausschliesst.
> Wenn ein Heap vorhanden ist, ist auto automatisch der Heap
Nein. Du verwechselst das mit einem Stack.
Der Heap ist keine storage class, ist auch nicht Teil der Kernsprache,
sondern kommt (in C) ausschliesslich in Bibliotheksfunktionen vor.
chris schrieb:> Es gab folgende storage class:> typedef> extern> auto> register> static> intern> Nur die letzten zwei sind mit 0 zu initialisieren.
Irgendwie redest du über ein anderes C als alle anderen.
"typedef" ist nur syntaktisch eine Speicherklasse; ist eine ziemliche
Krücke, aber interessiert hier sowieso nicht.
"intern" gibt es nicht in C.
"auto" und "register" sind heutzutage praktisch dasselbe.
"extern" kann nur in einer Deklaration verwendet werden, um ein
globales Objekt (oder eine globale Funktion) anzuzeigen. Diese muss
aber global in irgendeiner Übersetzungseinheit definiert werden.
"global" heißt in diesem Zusammenhang, dass sie außerhalb jeglicher
Funktionen und ohne das Schlüsselwort "static" stehen muss.
Speicherklassenmäßig werden globale und statische Objekte gleich
behandelt. Der Standard nennt dies "static storage duration".
Alle diese Objekte mit "static storage duration" werden, sofern sie
nicht explizit anders initialisiert werden, implizit mit 0
initialisiert. (Das ist die Kurzfassung, die offizielle Langfassung
wurde oben genannt.)
Das war schon immer so, darauf baut diese Sprache.
> Dass globale Variablen der Klasse static und locale Variablen der Klasse> auto zugewiesen werden, wie man es vielleicht in der Schule gelernt hat,> mag stimmen.> Diese Konvention ist aber nicht im Standard enthalten
Selbstverständlich ist sie das.
Wenn du das Gegenteil behauptest, solltest du die entsprechende Stelle
des Standards hier zitieren können.
> und Compiler für> Architekturen, welche keinen Heap haben, verwenden auto für globale> Variablen.
Sorry, aber das ist einfach Unfug. Mit einem Heap hat das hinten und
vorn nichts zu tun. Der kommt ausschließlich dann ins Spiel, wenn
eine dynamische Speicherverwaltung benötigt wird.
Aufgrund der bahnbrechenden Erkenntnis, dass dieses Schlüsselwort
überflüssig ist, wird es in C++11 anderweitig verwendet.
Stroustrup: "Several committee members trawled through millions of lines
of code finding only a handful of uses -- and most of those were in test
suites or appeared to be bugs."
Bronco schrieb:> Cool, ich wußte noch gar nicht, daß man in C++11 variadische Klassen> verwenden kann...
Das war nicht C++, sondern PHP.
„Der Compiler weiß dann schon, was der Programmierer gewollt hat.“
Bronco schrieb:> Cool, ich wußte noch gar nicht, daß man in C++11 variadische Klassen> verwenden kann...
tja, besser künstliche Intelligenz als gar keine :-)