Forum: Compiler & IDEs Programmiersprache C, Bedeutung von static bei globalen Variablen


von Micha (Gast)


Lesenswert?

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.

: Verschoben durch User
von Peter II (Gast)


Lesenswert?

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.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

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
static int bla = 4;
4
5
static int machwas(void)
6
{
7
  return bla;
8
}
9
10
int machwas_in_a(void)
11
{
12
  return machwas();
13
}


b.c
1
#include "b.h"
2
3
static int bla = 5;
4
5
static int machwas(void)
6
{
7
  return bla;
8
}
9
10
int machwas_in_b(void)
11
{
12
  return machwas();
13
}


a.h
1
int machwas_in_a(void);

b.h
1
int machwas_in_b(void);

main.c
1
#include <stdio.h>
2
3
#include "a.h"
4
#include "b.h"
5
6
int main(int, char**)
7
{
8
  printf("A: %d\n", machwas_in_a()); 
9
  printf("B: %d\n", machwas_in_b()); 
10
  return 0;
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.

von chris (Gast)


Lesenswert?

Abgesehen davon sind static Variablen auch mit Null initialisiert.
Dies wird deswegen auch gerne von Programmierern verwendet.

von radiostar (Gast)


Lesenswert?

chris schrieb:
> Abgesehen davon sind static Variablen

Globale sowieso!

von chris (Gast)


Lesenswert?

Im PC Bereich sowie GCC ja, ansonsten trifft man oft auf Systemen wo 
dies
nicht zutrifft.

von Peter II (Gast)


Lesenswert?

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.

von chris (Gast)


Lesenswert?

Habe extra in den Spezifikationen nachgesehen.
Seit C11 stimmt deine Aussage, aber von ANSI X3.159 bis incl C99
sieht es anders aus.

von Stefan E. (sternst)


Lesenswert?

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;

von (prx) A. K. (prx)


Lesenswert?

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.

von Stefan E. (sternst)


Lesenswert?

Und hier auch noch der entsprechende Passus aus ANSI-C:
1
   If an object that has static storage duration is not initialized
2
explicitly, it is initialized implicitly as if every member that has
3
arithmetic type were assigned 0 and every member that has pointer type
4
were assigned a null pointer constant.

von Reinhold_E (Gast)


Lesenswert?

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.

von Peter II (Gast)


Lesenswert?

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.

von chris (Gast)


Lesenswert?

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.

von Stefan E. (sternst)


Lesenswert?

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

von (prx) A. K. (prx)


Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Bronco (Gast)


Lesenswert?

Gibt es eigentlich einen Anwendungsfall, bei dem man eine Variable 
explizit als "auto" definiert?

von (prx) A. K. (prx)


Lesenswert?

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

von Klaus W. (mfgkw)


Lesenswert?

Bronco schrieb:
> Gibt es eigentlich einen Anwendungsfall, bei dem man eine Variable
> explizit als "auto" definiert?

Nur, um Leute zu verwirren:
1
class Auto
2
{
3
...
4
};
5
6
int main()
7
{
8
    auto Auto meinAuto;
9
    ...
10
}

von Yalu X. (yalu) (Moderator)


Lesenswert?

Klaus Wachtler schrieb:
> Nur, um Leute zu verwirren:

Vor allem die Benutzer von C++11 ;-)

von (prx) A. K. (prx)


Lesenswert?

Die schreiben dann eben
   auto meinAuto = Fahrrad();

von Klaus W. (mfgkw)


Lesenswert?

du hast vergessen, Fahrrad() in einen Laster zu casten vor der 
Zuweisung...

von Bronco (Gast)


Lesenswert?

Klaus Wachtler schrieb:
>
1
> class Auto
2
> {
3
> ...
4
> };

Cool, ich wußte noch gar nicht, daß man in C++11 variadische Klassen 
verwenden kann...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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

von Klaus W. (mfgkw)


Lesenswert?

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 :-)

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.