Programmiersprache C, Bedeutung von static bei globalen Variablen

Gast #3304859
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.
Gast #3304865
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.
Persönliche Seite #3304873
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.
#3304992
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;
#3305004
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.
Gast #3305024
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.
Gast #3305043
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.
Gast #3305061
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.
#3305089
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".
#3305090
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.
Moderator Persönliche Seite #3305101
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.
#3305330
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."

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren