title logo
title right side
12.08.2026 02:41:32 Lokal:
Serverstatus: (4.50/4.19/4.1764.87/1062.1 GByte  
Aussentemperatur : 19.1 °C  Luftdruck : 1026.19 hPas/mbar
Impressions: 2 
Visits heute: 196 

  Aktuelle Seite: Speicherklassen in C

Home  

In C bestimmen Speicherklassen (storage classes) vor allem, wo und wie lange eine Variable existiert und welche Sichtbarkeit bzw. Verknüpfung (Linkage) sie besitzt.

Die wichtigsten Schlüsselwörter sind:

  • auto
  • register
  • static
  • extern

Zusätzlich ist es wichtig, zwischen Speicherdauer (storage duration) und Sichtbarkeit/Linkage zu unterscheiden.


1. auto – die normale lokale Variable

auto ist für lokale Variablen die Standard-Speicherklasse.

void foo(void)
{
    auto int x = 10;
    int y = 20;       // identisch, auto ist implizit
}

x und y sind hier praktisch dasselbe.

Eigenschaften

  • lokal zur Funktion bzw. zum Block
  • wird beim Eintritt in den Block erzeugt
  • verschwindet beim Verlassen des Blocks
  • bei jedem erneuten Aufruf neu erzeugt
  • nicht automatisch initialisiert

Beispiel:

void counter(void)
{
    int count = 0;

    count++;

    printf("%d\n", count);
}

Bei:

counter();
counter();
counter();

kommt:

1
1
1

Denn count wird bei jedem Aufruf neu erzeugt und mit 0 initialisiert.

In modernem C schreibt man auto fast nie explizit. int count ist die übliche Schreibweise.


2. static innerhalb einer Funktion

Hier wird es interessant.

Eine lokale Variable mit static behält ihren Wert zwischen Funktionsaufrufen.

void counter(void)
{
    static int count = 0;

    count++;

    printf("%d\n", count);
}

Jetzt:

counter();
counter();
counter();

ergibt:

1
2
3

Obwohl count weiterhin nur innerhalb von counter() sichtbar ist, wird sie nicht bei jedem Aufruf neu erzeugt.

Das Entscheidende

                    sichtbar?       Lebensdauer
----------------------------------------------------
int count           nur in Funktion  bis Blockende
static int count    nur in Funktion  gesamtes Programm

Man kann sich static hier also als "lokale Variable mit dauerhaftem Gedächtnis" vorstellen.


Beispiel: Zustand einer Funktion

Das ist beispielsweise praktisch für eine Funktion, die wissen soll, wie oft sie aufgerufen wurde:

int get_next_id(void)
{
    static int id = 0;

    return ++id;
}

Dann:

printf("%d\n", get_next_id());
printf("%d\n", get_next_id());
printf("%d\n", get_next_id());

ergibt:

1
2
3

3. static auf Dateiebene

static hat außerhalb einer Funktion noch eine andere, sehr wichtige Bedeutung.

Betrachten wir:

/* motor.c */

static int speed = 100;

Diese Variable ist nur innerhalb von motor.c bekannt.

Sie kann also nicht von anderen Übersetzungseinheiten aus angesprochen werden.

Das Gleiche gilt für Funktionen:

static void calculate_speed(void)
{
    ...
}

calculate_speed() ist dann eine private Funktion dieses C-Moduls.

Das ist bei größeren C-Projekten extrem nützlich.


Beispiel

motor.c

#include "motor.h"

static int speed = 0;

static void update_pwm(void)
{
    ...
}

void motor_set_speed(int value)
{
    speed = value;
    update_pwm();
}

main.c

#include "motor.h"

int main(void)
{
    motor_set_speed(50);
}

main.c kann motor_set_speed() verwenden.

Aber:

speed = 100;

geht nicht.

Und:

update_pwm();

geht ebenfalls nicht.

Damit kann man ein Modul sauber kapseln.


4. extern – eine Variable befindet sich woanders

extern bedeutet im Wesentlichen:

Diese Variable existiert, aber ihre Definition befindet sich an einer anderen Stelle.

Beispielsweise:

config.c

int debug_level = 2;

Das ist die Definition.

In einer anderen Datei:

main.c

extern int debug_level;

int main(void)
{
    printf("%d\n", debug_level);
}

Hier ist debug_level nur deklariert.

Der Compiler bekommt damit die Information:

Es gibt irgendwo ein int debug_level.

Der Linker findet später die eigentliche Definition in config.c.


Noch besser: Header-Datei

Typischerweise macht man:

config.h

#ifndef CONFIG_H
#define CONFIG_H

extern int debug_level;

#endif

config.c

#include "config.h"

int debug_level = 2;

main.c

#include <stdio.h>
#include "config.h"

int main(void)
{
    printf("Debug-Level: %d\n", debug_level);
}

Das ist eine typische C-Projektstruktur.


5. register – bitte in Ruhe lassen

register ist historisch interessant.

register int i;

Damit konnte man dem Compiler früher einen Hinweis geben:

Diese Variable wird sehr häufig benutzt; leg sie möglichst in einem CPU-Register ab.

Früher war das durchaus relevant.

Heute optimieren moderne Compiler wesentlich besser:

gcc -O2
gcc -O3

Der Compiler entscheidet selbst, ob eine Variable in einem Register landet.

Deshalb schreibt man normalerweise einfach:

int i;

und überlässt die Optimierung dem Compiler.


6. Ein wichtiger Unterschied: Initialisierung

Hier lauert eine typische Falle.

Eine normale lokale Variable:

void foo(void)
{
    int x;

    printf("%d\n", x);   // FEHLER: undefinierter Wert
}

hat keinen definierten Anfangswert.

Eine static-Variable dagegen wird automatisch mit 0 initialisiert:

void foo(void)
{
    static int x;

    printf("%d\n", x);   // 0
}

Das gilt auch für globale Variablen:

int global;

global beginnt mit:

0

7. static wird automatisch initialisiert

Das gilt auch für komplexere Datentypen:

static int values[10];

Alle Elemente sind zunächst:

0 0 0 0 0 0 0 0 0 0

Auch:

static char buffer[1024];

ist vollständig mit '\0' initialisiert.

Das ist beispielsweise bei Puffern sehr praktisch.


8. Die vier Speicherklassen im Überblick

Speicherklasse Typischer Ort Lebensdauer Sichtbarkeit
auto lokal Block Block
register lokal Block Block
static lokal lokal gesamtes Programm Block
static global Datei gesamtes Programm nur diese Datei
extern global gesamtes Programm über Dateien hinweg

Dabei ist extern etwas anders als die anderen: Es beschreibt hauptsächlich eine Deklaration bzw. externe Verknüpfung, nicht einfach einen bestimmten Speicherort.


9. Besonders wichtig: static hat zwei Bedeutungen

Das ist wahrscheinlich die wichtigste Sache, die man sich merken sollte.

Innerhalb einer Funktion

void foo(void)
{
    static int x;
}

bedeutet:

x bleibt über Funktionsaufrufe hinweg erhalten.

Außerhalb einer Funktion

static int x;

bedeutet:

x ist nur in dieser Quelldatei sichtbar.

Und:

static void foo(void)
{
}

bedeutet:

foo() ist nur in dieser Quelldatei sichtbar.


10. Zusammenspiel in einem echten C-Modul

Nehmen wir beispielsweise ein kleines Motor-Modul:

motor.c

#include "motor.h"

static int current_speed = 0;

static void update_hardware(void)
{
    printf("PWM = %d\n", current_speed);
}

void motor_set_speed(int speed)
{
    current_speed = speed;
    update_hardware();
}

int motor_get_speed(void)
{
    return current_speed;
}

Hier sind:

static int current_speed;

und

static void update_hardware(void)

private Implementierungsdetails.

Nach außen gibt es nur:

void motor_set_speed(int speed);
int motor_get_speed(void);

Der Header könnte deshalb so aussehen:

#ifndef MOTOR_H
#define MOTOR_H

void motor_set_speed(int speed);
int motor_get_speed(void);

#endif

Das ist ein sehr schönes Beispiel dafür, wie man mit static in C eine Art Kapselung erreicht.


11. Speicherklasse ist nicht dasselbe wie Speicherort

Ein häufiger Denkfehler ist:

static bedeutet "liegt im RAM".

Das ist so nicht ganz richtig.

Die Speicherklasse beschreibt Eigenschaften wie Lebensdauer und Linkage. Der tatsächliche Speicherort kann beispielsweise sein:

Stack
Heap
Data Segment
BSS
Register
...

Zum Beispiel:

void foo(void)
{
    int a;
    static int b;
}

Typischerweise könnte das vereinfacht so aussehen:

Stack:
    a

statischer Speicher:
    b

a verschwindet nach dem Verlassen von foo().

b bleibt während der gesamten Programmlaufzeit erhalten.


12. Ein schönes Gesamtbeispiel

#include <stdio.h>

int global = 10;

static int private_global = 20;

void test(void)
{
    int normal = 0;
    static int persistent = 0;

    normal++;
    persistent++;

    printf("normal:     %d\n", normal);
    printf("persistent: %d\n", persistent);
}

int main(void)
{
    test();
    test();
    test();

    printf("global: %d\n", global);
    printf("private: %d\n", private_global);

    return 0;
}

Ausgabe:

normal:     1
persistent: 1
normal:     1
persistent: 2
normal:     1
persistent: 3

global: 10
private: 20

Der entscheidende Unterschied ist:

normal
  │
  ├── Aufruf 1 → 0 → 1 → zerstört
  ├── Aufruf 2 → 0 → 1 → zerstört
  └── Aufruf 3 → 0 → 1 → zerstört


persistent
  │
  ├── Aufruf 1 → 0 → 1
  ├── Aufruf 2 → 1 → 2
  └── Aufruf 3 → 2 → 3

Meine praktische Faustregel

Beim Programmieren in C brauchst du in der Praxis hauptsächlich diese drei Muster:

/* normale lokale Variable */
int value;
/* dauerhaft, aber nur innerhalb dieser Funktion */
static int value;
/* privat für dieses C-Modul */
static int value;
static void helper(void);

Und für Variablen, die zwischen mehreren .c-Dateien geteilt werden:

/* header.h */
extern int value;
/* source.c */
int value = 42;

register kannst du bei modernem C praktisch vergessen.

Wenn du C auf etwas fortgeschrittenerem Niveau betreibst, ist als nächstes besonders interessant, wie static, extern, const und volatile miteinander kombiniert werden – gerade bei deinen C-Projekten mit mehreren .c/.h-Dateien und Mikrocontrollern ist das sehr relevant.