Спецификаторы класса хранения
Задают длительность хранения и связь объектов и функций:
-
auto— автоматическая длительность хранения и отсутствие связи -
register— автоматическая длительность хранения и отсутствие связи; адрес этой переменной нельзя получить -
static— статическая длительность хранения и внутренняя связь (кроме блочной области видимости) -
extern— статическая длительность хранения и внешняя связь (если ранее не была объявлена внутренняя связь)
| (начиная с C11) |
Пояснение
Спецификаторы класса хранения встречаются в объявлениях и выражениях составных литералов(начиная с C23). Можно использовать не более одного спецификатора, за исключением того, что _Thread_local(до C23)thread_local(начиная с C23) можно сочетать с static или extern для изменения связи(начиная с C11). Спецификаторы класса хранения задают два независимых свойства объявляемых ими имён: длительность хранения и связь.
_Alignas(до C23)alignas(начиная с C23)(начиная с C11), а массивы register не преобразуются в указатели.| 5) _Thread_local(до C23)thread_local(начиная с C23) задаёт длительность хранения потока. Его нельзя использовать в объявлениях функций. Если он используется в объявлении объекта, он должен присутствовать во всех объявлениях того же объекта. Если он используется в объявлении в блочной области видимости, его необходимо сочетать с static или extern, чтобы определить связь. | (начиная с C11) |
Если спецификатор класса хранения не указан, используются следующие значения по умолчанию:
- extern для всех функций
- extern для объектов в области видимости файла
- auto для объектов в блочной области видимости
Для любой структуры или объединения, объявленных со спецификатором класса хранения, длительность хранения (но не связь) распространяется на их члены рекурсивно.
В объявлениях функций в блочной области видимости можно использовать extern или не использовать спецификатор вовсе. В объявлениях функций в области видимости файла можно использовать extern или static.
Для параметров функций нельзя использовать спецификаторы класса хранения, кроме register. Обратите внимание, что static имеет особое значение для параметров функций массивного типа.
Длительность хранения
Каждый объект обладает свойством, называемым длительностью хранения, которое ограничивает время жизни объекта. В C предусмотрено четыре вида длительности хранения:
- автоматическая длительность хранения. Память выделяется при входе в блок, в котором объявлен объект, и освобождается при выходе из него любым способом (goto, return, достижение конца блока). Исключение составляют VLA: память для них выделяется при выполнении объявления, а не при входе в блок, и освобождается, когда объявление выходит из области видимости, а не при выходе из блока(начиная с C99). При рекурсивном входе в блок для каждого уровня рекурсии выполняется новое выделение памяти. Все параметры функций и объекты блочной области видимости, не объявленные с static, имеют такую длительность хранения, как и составные литералы, используемые в блочной области видимости(до C23)
- статическая длительность хранения. Длительность хранения охватывает всё выполнение программы, а сохранённое в объекте значение инициализируется только один раз, до вызова функции main. Все объекты, объявленные с static, и все объекты с внутренней или внешней связью, не объявленные с _Thread_local(до C23)thread_local(начиная с C23)(начиная с C11), имеют такую длительность хранения.
| (начиная с C11) |
- выделяемая длительность хранения. Память выделяется и освобождается по запросу с помощью функций динамического выделения памяти.
Связь
Связь определяет, можно ли обращаться к идентификатору (переменной или функции) из других областей видимости. Если переменная или функция с одним и тем же идентификатором объявлена в нескольких областях видимости, но доступна не из всех них, создаётся несколько экземпляров переменной. Различают следующие виды связи:
-
отсутствие связи. К переменной или функции можно обращаться только из той области видимости, в которой она находится (блочная область видимости). Все переменные блочной области видимости, не объявленные
extern, имеют такую связь, как и все параметры функций и все идентификаторы, которые не являются функциями или переменными. -
внутренняя связь. К переменной или функции можно обращаться из всех областей видимости в текущей единице трансляции. Все переменные области видимости файла, объявленные
staticилиconstexpr(начиная с C23), имеют такую связь, как и все функции области видимости файла, объявленныеstatic(объявления статических функций разрешены только в области видимости файла). -
внешняя связь. К переменной или функции можно обращаться из любых других единиц трансляции программы. Все переменные области видимости файла, не объявленные
staticилиconstexpr(начиная с C23), имеют такую связь; такую же связь имеют все объявления функций в области видимости файла, не объявленныеstatic, все объявления функций в блочной области видимости, а также все переменные или функции, объявленныеextern, если в этой точке видимости нет предшествующего объявления с внутренней связью.
Если один и тот же идентификатор имеет и внутреннюю, и внешнюю связь в одной единице трансляции, поведение не определено. Это возможно при использовании предварительных определений.
Связь и библиотеки
Объявления с внешней связью обычно размещают в заголовочных файлах, чтобы все единицы трансляции, которые подключают этот файл, могли обращаться к одному и тому же идентификатору, определённому в другом месте.
Любое объявление с внутренней связью, размещённое в заголовочном файле, приводит к созданию отдельного самостоятельного объекта в каждой единице трансляции, подключающей этот файл.
| Интерфейс библиотеки, заголовочный файл "flib.h": #ifndef FLIB_H
#define FLIB_H
void f(void); // function declaration with external linkage
extern int state; // variable declaration with external linkage
static const int size = 5; // definition of a read-only variable with internal linkage
enum { MAX = 10 }; // constant definition
inline int sum (int a, int b) { return a + b; } // inline function definition
#endif // FLIB_H
Реализация библиотеки, исходный файл "flib.c": #include "flib.h"
static void local_f(int s) {} // definition with internal linkage (only used in this file)
static int local_state; // definition with internal linkage (only used in this file)
int state; // definition with external linkage (used by main.c)
void f(void) { local_f(state); } // definition with external linkage (used by main.c)
Код приложения, исходный файл "main.c": #include "flib.h"
int main(void)
{
int x[MAX] = {size}; // uses the constant and the read-only variable
state = 7; // modifies state in flib.c
f(); // calls f() in flib.c
}
|
Ключевые слова
auto, register, static, extern, _Thread_local thread_local
Примечания
| Ключевое слово _Thread_local обычно используется с помощью удобного макроса | (до C23) |
Спецификаторы typedef и constexpr(начиная с C23) формально перечислены в грамматике языка C как спецификаторы класса хранения, но не задают хранение.
| Спецификатор auto также используется для вывода типа. | (начиная с C23) |
Имена в области видимости файла, имеющие квалификатор const и не имеющие extern, в C обладают внешней связью (как и все объявления в области видимости файла по умолчанию), а в C++ — внутренней связью.
Пример
#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
}
Возможный вывод:
&A = 0x600ae4 &A = 0x7ffefb064f5c address of int in allocated memory = 0x1f28c30
Ссылки
- Стандарт C23 (ISO/IEC 9899:2024):
- 6.2.2 Связь идентификаторов (с. 35–36)
- 6.2.4 Длительность хранения объектов (с. 36–37)
- 6.7.1 Спецификаторы класса хранения (с. 97–100)
- Стандарт C17 (ISO/IEC 9899:2018):
- 6.2.2 Связь идентификаторов (с. 29–30)
- 6.2.4 Длительность хранения объектов (с. 30)
- 6.7.1 Спецификаторы класса хранения (с. 79)
- Стандарт C11 (ISO/IEC 9899:2011):
- 6.2.2 Связь идентификаторов (с. 36–37)
- 6.2.4 Длительность хранения объектов (с. 38–39)
- 6.7.1 Спецификаторы класса хранения (с. 109–110)
- Стандарт C99 (ISO/IEC 9899:1999):
- 6.2.2 Связь идентификаторов (с. 30–31)
- 6.2.4 Длительность хранения объектов (с. 32)
- 6.7.1 Спецификаторы класса хранения (с. 98–99)
- Стандарт C89/C90 (ISO/IEC 9899:1990):
- 3.1.2.2 Связь идентификаторов
- 3.1.2.4 Длительность хранения объектов
- 3.5.1 Спецификаторы класса хранения
См. также
| Документация по C++ для спецификаторов класса хранения |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/c/language/storage_duration