Storage-class specifiers
Укажите storage duration и linkage объектов и функций:
-
-
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 существует четыре вида продолжительности хранения:
-
- automatic продолжительность хранения. Память выделяется при входе в блок , в котором объявлен объект, и освобождается при выходе из него любым способом ( goto , return , достижение конца). Исключением являются VLA ; их память выделяется при выполнении объявления, а не при входе в блок, и освобождается при выходе объявления из области видимости, а не при выходе из блока (начиная с C99) . Если блок входит рекурсивно, новое выделение выполняется для каждого уровня рекурсии. Все параметры функций и не- static объекты блочной области видимости имеют эту продолжительность хранения, а также составные литералы , используемые в блочной области видимости (до C23)
- static продолжительность хранения. Продолжительность хранения охватывает всё время выполнения программы, и значение, хранящееся в объекте, инициализируется только один раз, до вызова функции main . Все объекты, объявленные как static , и все объекты с внутренней или внешней линковкой которые не объявлены _Thread_local (до C23) thread_local (начиная с C23) (начиная с C11) имеют эту продолжительность хранения.
|
(since C11) |
-
- allocated продолжительность хранения. Память выделяется и освобождается по запросу с использованием функций динамического выделения памяти .
Связывание
Связывание (linkage) относится к способности идентификатора (переменной или функции) быть упомянутым в других областях видимости. Если переменная или функция с одинаковым идентификатором объявлена в нескольких областях видимости, но не может быть упомянута из всех них, то создаются несколько экземпляров переменной. Различают следующие виды связывания:
-
-
отсутствие связи
. На переменную или функцию можно ссылаться только из той области видимости, в которой она находится (область видимости блока). Все переменные области видимости блока, которые не объявлены как
extern, имеют эту связь, а также все параметры функций и все идентификаторы, не являющиеся функциями или переменными.
-
отсутствие связи
. На переменную или функцию можно ссылаться только из той области видимости, в которой она находится (область видимости блока). Все переменные области видимости блока, которые не объявлены как
-
-
внутренняя линковка
. Переменная или функция может быть использована из всех областей видимости в текущей единице трансляции. Все переменные области видимости файла, объявленные как
staticилиconstexpr(начиная с C23) , имеют эту линковку, как и все функции области видимости файла, объявленные какstatic(объявления статических функций разрешены только в области видимости файла).
-
внутренняя линковка
. Переменная или функция может быть использована из всех областей видимости в текущей единице трансляции. Все переменные области видимости файла, объявленные как
-
-
внешняя компоновка
. Переменная или функция может быть использована из любых других единиц трансляции во всей программе. Все переменные области видимости файла, которые не объявлены
staticилиconstexpr(начиная с C23) , имеют эту компоновку, все объявления функций области видимости файла, которые не объявленыstatic, все объявления функций области видимости блока, и, дополнительно, все переменные или функции, объявленныеextern, имеют эту компоновку, если в данной точке не видно предыдущее объявление с внутренней компоновкой.
-
внешняя компоновка
. Переменная или функция может быть использована из любых других единиц трансляции во всей программе. Все переменные области видимости файла, которые не объявлены
Если один и тот же идентификатор появляется одновременно с внутренней и внешней линковкой в одной единице трансляции, поведение не определено. Это возможно при использовании tentative definitions .
Линковка и библиотеки
|
Этот раздел не завершён
Причина: должно ли это быть отдельной записью верхнего уровня в c/language в разделе Разное? |
Объявления с внешней линковкой обычно предоставляются в заголовочных файлах, чтобы все единицы трансляции, которые #include этот файл, могли ссылаться на один и тот же идентификатор, определённый в другом месте.
Любое объявление с внутренней линковкой, которое появляется в заголовочном файле, приводит к созданию отдельного и уникального объекта в каждой единице трансляции, включающей этот файл.
Интерфейс библиотеки, заголовочный файл "flib.h":
#ifndef FLIB_H #define FLIB_H void f(void); // объявление функции с внешней линковкой extern int state; // объявление переменной с внешней линковкой static const int size = 5; // определение переменной только для чтения с внутренней линковкой enum { MAX = 10 }; // определение константы inline int sum (int a, int b) { return a + b; } // определение встроенной функции #endif // FLIB_H
Реализация библиотеки, исходный файл "flib.c":
#include "flib.h" static void local_f(int s) {} // определение с внутренней линковкой (используется только в этом файле) static int local_state; // определение с внутренней линковкой (используется только в этом файле) int state; // определение с внешней линковкой (используется в main.c) void f(void) { local_f(state); } // определение с внешней линковкой (используется в main.c)
Код приложения, исходный файл "main.c":
#include "flib.h" int main(void) { int x[MAX] = {size}; // использует константу и переменную только для чтения state = 7; // изменяет state в flib.c f(); // вызывает f() в flib.c }
Ключевые слова
auto , register , static , extern , _Thread_local thread_local
Примечания
|
Ключевое слово _Thread_local обычно используется через удобный макрос thread_local , определённый в заголовочном файле <threads.h> . |
(до C23) |
Спецификаторы
typedef
и
constexpr
(начиная с C23)
формально перечислены как спецификаторы класса хранения в грамматике языка C, но не определяют хранение.
|
Спецификатор auto также используется для вывода типа. |
(since 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++ documentation
for
Storage class specifiers
|