Namespaces
Variants

Storage-class specifiers

From cppreference.net

Bestimmen Sie die Speicherdauer und Verknüpfung von Objekten und Funktionen:

  • auto - automatische Speicherdauer und keine Verknüpfung
  • register - automatische Speicherdauer und keine Verknüpfung; Adresse dieser Variable kann nicht genommen werden
  • static - statische Speicherdauer und interne Verknüpfung (außer bei Blockgültigkeit)
  • extern - statische Speicherdauer und externe Verknüpfung (sofern nicht bereits als intern deklariert)
  • _Thread_local (bis C23) thread_local (seit C23) - Thread-Speicherdauer
(seit C11)

Inhaltsverzeichnis

Erklärung

Speicherklassenspezifizierer erscheinen in Deklarationen und Compound-Literal Ausdrücken (seit C23) . Höchstens ein Spezifizierer darf verwendet werden , außer dass _Thread_local (bis C23) thread_local (seit C23) kombiniert werden kann mit static oder extern zur Anpassung der Verknüpfung (seit C11) . Die Speicherklassenspezifizierer bestimmen zwei unabhängige Eigenschaften der von ihnen deklarierten Namen: Speicherdauer und Verknüpfung .

1) Der auto -Spezifizierer ist nur für Objekte zulässig, die im Blockbereich deklariert sind (außer Funktionsparameterlisten). Er zeigt automatische Speicherdauer und keine Bindung an, was die Standardeinstellungen für diese Art von Deklarationen sind.
2) Der register -Spezifizierer ist nur für Objekte erlaubt, die im Blockbereich deklariert sind, einschließlich Funktionsparameterlisten. Er gibt automatische Speicherdauer und keine Verknüpfung an (was der Standard für diese Art von Deklarationen ist), gibt dem Optimierer jedoch zusätzlich den Hinweis, den Wert dieser Variable nach Möglichkeit in einem CPU-Register zu speichern. Unabhängig davon, ob diese Optimierung stattfindet oder nicht, können als register deklarierte Variablen nicht als Argumente für den Adressoperator verwendet werden , können nicht _Alignas (bis C23) alignas (seit C23) (seit C11) verwenden, und register -Arrays sind nicht in Zeiger konvertierbar.
3) Der static Spezifizierer legt sowohl die statische Speicherdauer (sofern nicht kombiniert mit _Thread_local ) (seit C11) als auch interne Bindung fest (sofern nicht im Blockbereich verwendet). Er kann mit Funktionen auf Dateiebene und mit Variablen sowohl auf Datei- als auch Blockebene verwendet werden, jedoch nicht in Funktionsparameterlisten.
4) Der extern Spezifizierer legt eine statische Speicherdauer fest (sofern nicht kombiniert mit _Thread_local (bis C23) thread_local (seit C23) ) (seit C11) und externe Bindung. Er kann bei Funktions- und Objektdeklarationen sowohl im Datei- als auch im Blockbereich verwendet werden (ausgenommen Funktionsparameterlisten). Wenn extern bei einer Neudeklaration einer Identifikation erscheint, die bereits mit interner Bindung deklariert wurde, bleibt die Bindung intern. Andernfalls (wenn die vorherige Deklaration extern, ohne Bindung war oder nicht im Gültigkeitsbereich liegt) ist die Bindung extern.
5) _Thread_local (bis C23) thread_local (seit C23) kennzeichnet Thread-Speicherdauer . Es kann nicht mit Funktionsdeklarationen verwendet werden. Wenn es bei der Deklaration eines Objekts verwendet wird, muss es bei jeder Deklaration desselben Objekts vorhanden sein. Wenn es bei einer Blockbereichsdeklaration verwendet wird, muss es entweder mit static oder extern kombiniert werden, um die Linkage zu bestimmen.
(seit C11)

Wenn kein Speicherklassenspezifizierer angegeben wird, sind die Standardwerte:

extern für alle Funktionen
extern für Objekte im Dateigültigkeitsbereich
auto für Objekte im Blockgültigkeitsbereich

Für jede Struktur oder Union, die mit einem Speicherklassenspezifizierer deklariert wird, gilt die Speicherdauer (jedoch nicht die Bindung) für ihre Mitglieder, rekursiv.

Funktionsdeklarationen im Blockbereich können extern oder gar keine Spezifizierer verwenden. Funktionsdeklarationen im Dateibereich können extern oder static verwenden.

Funktionsparameter dürfen keine anderen Speicherklassenspezifizierer als register verwenden. Beachten Sie, dass static eine spezielle Bedeutung bei Funktionsparametern vom Array-Typ hat.

Speicherdauer

Jedes Objekt besitzt eine Eigenschaft namens Speicherdauer , die die Lebensdauer des Objekts begrenzt. Es gibt vier Arten von Speicherdauer in C:

  • automatic Speicherdauer. Der Speicher wird zugewiesen, wenn der Block betreten wird, in dem das Objekt deklariert wurde, und freigegeben, wenn er auf beliebige Weise verlassen wird ( goto , return , Erreichen des Endes). Eine Ausnahme sind VLAs ; ihr Speicher wird bei Ausführung der Deklaration zugewiesen, nicht beim Blockeintritt, und freigegeben, wenn die Deklaration den Gültigkeitsbereich verlässt, nicht wenn der Block verlassen wird (seit C99) . Wenn der Block rekursiv betreten wird, erfolgt für jede Rekursionsebene eine neue Zuweisung. Alle Funktionsparameter und nicht- static Blockbereichsobjekte haben diese Speicherdauer, sowie compound literals die im Blockbereich verwendet werden (bis C23)
  • static Speicherdauer. Die Speicherdauer umfasst die gesamte Programmausführung, und der im Objekt gespeicherte Wert wird nur einmal initialisiert, vor der main-Funktion . Alle mit static deklarierten Objekte und alle Objekte mit interner oder externer Verknüpfung die nicht als _Thread_local (bis C23) thread_local (seit C23) deklariert sind (seit C11) haben diese Speicherdauer.
  • thread Speicherdauer. Die Speicherdauer ist die gesamte Ausführungszeit des Threads, in dem es erstellt wurde, und der im Objekt gespeicherte Wert wird beim Start des Threads initialisiert. Jeder Thread hat sein eigenes, eindeutiges Objekt. Wenn der Thread, der den Ausdruck ausführt, der auf dieses Objekt zugreift, nicht der Thread ist, der seine Initialisierung ausgeführt hat, ist das Verhalten implementierungsdefiniert. Alle deklarierten Objekte _Thread_local (bis C23) thread_local (seit C23) haben diese Speicherdauer.
(seit C11)

Verknüpfung

Linkage bezieht sich auf die Fähigkeit eines Identifikators (Variable oder Funktion), in anderen Gültigkeitsbereichen referenziert zu werden. Wenn eine Variable oder Funktion mit demselben Identifikator in mehreren Gültigkeitsbereichen deklariert wird, aber nicht von allen referenziert werden kann, dann werden mehrere Instanzen der Variable erzeugt. Die folgenden Linkage-Arten werden unterschieden:

  • keine Verknüpfung . Auf die Variable oder Funktion kann nur aus dem Gültigkeitsbereich heraus zugegriffen werden, in dem sie sich befindet (Blockgültigkeitsbereich). Alle Blockgültigkeitsbereich-Variablen, die nicht als extern deklariert sind, haben diese Verknüpfung, ebenso alle Funktionsparameter und alle Bezeichner, die keine Funktionen oder Variablen sind.
  • internal linkage . Auf die Variable oder Funktion kann von allen Gültigkeitsbereichen in der aktuellen Übersetzungseinheit aus zugegriffen werden. Alle Dateibereichsvariablen, die als static oder constexpr (seit C23) deklariert sind, haben diese Bindung, ebenso wie alle Dateibereichsfunktionen, die als static deklariert sind (statische Funktionsdeklarationen sind nur im Dateibereich erlaubt).
  • external linkage . Die Variable oder Funktion kann von allen anderen Übersetzungseinheiten im gesamten Programm referenziert werden. Alle Dateibereichsvariablen, die nicht als static oder constexpr (since C23) deklariert sind, haben diese Bindung, alle Dateibereichsfunktionsdeklarationen, die nicht als static deklariert sind, alle Blockbereichsfunktionsdeklarationen und zusätzlich alle Variablen oder Funktionen, die als extern deklariert sind, haben diese Bindung, sofern keine vorherige Deklaration mit interner Bindung an dieser Stelle sichtbar ist.

Wenn derselbe Bezeichner im selben Übersetzungseinheit sowohl mit interner als auch externer Verknüpfung erscheint, ist das Verhalten undefiniert. Dies ist möglich, wenn vorläufige Definitionen verwendet werden.

Verknüpfung und Bibliotheken

Deklarationen mit externer Bindung werden üblicherweise in Header-Dateien bereitgestellt, damit alle Übersetzungseinheiten, die #include die Datei auf dieselben Bezeichner verweisen können, die an anderer Stelle definiert sind.

Jede Deklaration mit interner Verknüpfung, die in einer Header-Datei erscheint, führt zu einem separaten und eigenständigen Objekt in jeder Übersetzungseinheit, die diese Datei einbindet.

Bibliotheksschnittstelle, Header-Datei "flib.h":

#ifndef FLIB_H
#define FLIB_H
void f(void);              // Funktionsdeklaration mit externer Bindung
extern int state;          // Variablendeklaration mit externer Bindung
static const int size = 5; // Definition einer schreibgeschützten Variable mit interner Bindung
enum { MAX = 10 };         // Konstantendefinition
inline int sum (int a, int b) { return a + b; } // Inline-Funktionsdefinition
#endif // FLIB_H

Bibliotheksimplementierung, Quelldatei "flib.c":

#include "flib.h"
static void local_f(int s) {} // Definition mit internem Linkage (nur in dieser Datei verwendet)
static int local_state;       // Definition mit internem Linkage (nur in dieser Datei verwendet)
int state;                       // Definition mit externem Linkage (wird von main.c verwendet)
void f(void) { local_f(state); } // Definition mit externem Linkage (wird von main.c verwendet)

Anwendungscode, Quelldatei "main.c":

#include "flib.h"
int main(void)
{
    int x[MAX] = {size}; // verwendet die Konstante und die schreibgeschützte Variable
    state = 7;           // modifiziert state in flib.c
    f();                 // ruft f() in flib.c auf
}

Schlüsselwörter

auto , register , static , extern , _Thread_local thread_local

Hinweise

Das Schlüsselwort _Thread_local wird normalerweise über das praktische Makro thread_local verwendet, das im Header <threads.h> definiert ist.

(bis C23)

Die typedef und constexpr (seit C23) Spezifizierer sind formal in der C-Sprachgrammatik als Speicherklassen-Spezifizierer aufgeführt, legen jedoch keinen Speicher fest.

Der auto-Spezifizierer wird ebenfalls für Typinferenz verwendet.

(since C23)

Namen im Dateibereich, die const und nicht extern sind, haben externe Bindung in C (als Standard für alle Deklarationen im Dateibereich), aber interne Bindung in C++.

Beispiel

#include <stdio.h>
#include <stdlib.h>
// static storage duration
int A;
int main(void)
{
    printf("&A = %p\n", (void*)&A);
    // automatic storage duration
    int A = 1;   // hides global A
    printf("&A = %p\n", (void*)&A);
    // allocated storage duration
    int* ptr_1 = malloc(sizeof(int));   // start allocated storage duration
    printf("address of int in allocated memory = %p\n", (void*)ptr_1);
    free(ptr_1);                        // stop allocated storage duration
}

Mögliche Ausgabe:

&A = 0x600ae4
&A = 0x7ffefb064f5c
address of int in allocated memory = 0x1f28c30

Referenzen

  • C23-Standard (ISO/IEC 9899:2024):
  • 6.2.2 Verknüpfungen von Bezeichnern (S: 35-36)
  • 6.2.4 Speicherdauern von Objekten (S: 36-37)
  • 6.7.1 Speicherklassen-Spezifizierer (S: 97-100)
  • C17-Standard (ISO/IEC 9899:2018):
  • 6.2.2 Verknüpfungen von Bezeichnern (S: 29-30)
  • 6.2.4 Speicherdauer von Objekten (S: 30)
  • 6.7.1 Speicherklassenspezifizierer (S: 79)
  • C11-Standard (ISO/IEC 9899:2011):
  • 6.2.2 Verknüpfungen von Bezeichnern (S: 36-37)
  • 6.2.4 Speicherdauern von Objekten (S: 38-39)
  • 6.7.1 Speicherklassenspezifizierer (S: 109-110)
  • C99-Standard (ISO/IEC 9899:1999):
  • 6.2.2 Verknüpfungen von Bezeichnern (S: 30-31)
  • 6.2.4 Speicherdauer von Objekten (S: 32)
  • 6.7.1 Speicherklassenspezifizierer (S: 98-99)
  • C89/C90-Standard (ISO/IEC 9899:1990):
  • 3.1.2.2 Verknüpfungen von Bezeichnern
  • 3.1.2.4 Speicherdauern von Objekten
  • 3.5.1 Speicherklassenspezifizierer

Siehe auch

C++ Dokumentation für Storage class specifiers