Spec-Zone.ru › C

Спецификаторы класса хранения

Указывают длительность хранения и связь объектов и функций:

  • auto - автоматическая длительность хранения и отсутствие связи
  • register - автоматическая длительность хранения и отсутствие связи; адрес этой переменной нельзя получить
  • static - статическая длительность хранения и внутренняя связь (если не в области блока)
  • extern - статическая длительность хранения и внешняя связь (если не объявлена как внутренняя)
  • _Thread_local(до C23)thread_local(с C23) - длительность хранения потока
(с C11)

Объяснение

Спецификаторы класса хранения появляются в объявлениях и выражениях сложных литералов(с C23). Может использоваться не более одного спецификатора, за исключением того, что _Thread_local(до C23)thread_local(с C23) может быть объединён с static или extern для корректировки связи(с C11). Спецификаторы класса хранения определяют две независимые свойства объявляемых ими имен: длительность хранения и связь.

1) Спецификатор auto разрешён только для объектов, объявленных в области блока (за исключением списков параметров функций). Он указывает на автоматическую длительность хранения и отсутствие связи, которые являются значениями по умолчанию для объявлений этого типа.
2) Спецификатор register разрешён только для объектов, объявленных в области блока, включая списки параметров функций. Он указывает на автоматическую длительность хранения и отсутствие связи (которое является значением по умолчанию для объявлений этого типа), но также подсказывает оптимизатору хранить значение этой переменной в регистре процессора, если это возможно. Независимо от того, произойдёт ли эта оптимизация или нет, переменные, объявленные register, не могут использоваться в качестве аргументов для оператора взятия адреса, нельзя использовать alignas(с C11), и массивы register не преобразуются в указатели.
3) Спецификатор static задаёт статическую длительность хранения (если не объединён с _Thread_local)(с C11) и внутреннюю связь (если не используется в области блока). Он может использоваться с функциями в области файла и с переменными как в области файла, так и в области блока, но не в списках параметров функций.
4) Спецификатор extern задаёт статическую длительность хранения (если не объединён с _Thread_local(до C23)thread_local(с C23))(с C11) и внешнюю связь. Он может использоваться с объявлениями функций и объектов как в области файла, так и в области блока (исключая списки параметров функций). Если extern появляется в повторном объявлении идентификатора, который уже был объявлен с внутренней связью, связь остаётся внутренней. В противном случае (если предыдущее объявление было внешним, без связи или не находится в области видимости), связь является внешней.
5) _Thread_local(до C23)thread_local(с C23) указывает на длительность хранения потока. Он не может использоваться с объявлениями функций. Если он используется в объявлении объекта, он должен присутствовать в каждом объявлении того же объекта. Если он используется в объявлении в области блока, он должен быть объединён с static или extern для определения связи. (с C11)

Если спецификатор класса хранения не указан, значения по умолчанию:

extern для всех функций
extern для объектов в области файла
auto для объектов в области блока

Для любого структуры или объединения, объявленного со спецификатором класса хранения, длительность хранения (но не связь) применяется к их членам, рекурсивно.

Объявления функций в области блока могут использовать extern или вообще ничего. Объявления функций в области файла могут использовать extern или static.

Параметры функций не могут использовать спецификаторы класса хранения, кроме register. Обратите внимание, что static имеет специальное значение в параметрах функций типа массива.

Длительность хранения

Каждый объект имеет свойство, называемое длительностью хранения, которое ограничивает жизненный цикл объекта. В C существует четыре вида длительности хранения:

  • автоматическая длительность хранения. Хранение выделяется при входе в блок, в котором был объявлен объект, и освобождается при выходе из него любым способом (goto, return, достижение конца). Исключение составляют переменные длины массива (VLAs); их хранение выделяется при выполнении объявления, а не при входе в блок, и освобождается при выходе из области видимости объявления, а не при выходе из блока(с C99). Если блок вводится рекурсивно, выделение выполняется для каждого уровня рекурсии. Все параметры функций и не-static объекты в области блока имеют такую длительность хранения, а также сложные литералы, используемые в области блока(до C23)
  • статическая длительность хранения. Длительность хранения — это весь период выполнения программы, и значение, хранящееся в объекте, инициализируется только один раз до функции main. Все объекты, объявленные static, и все объекты с внутренней или внешней связью которые не объявлены _Thread_local(до C23)thread_local(с C23)(с C11) имеют такую длительность хранения.
  • потока длительность хранения. Длительность хранения — это весь период выполнения потока, в котором он был создан, и значение, хранящееся в объекте, инициализируется при запуске потока. Каждый поток имеет свой собственный, отдельный, объект. Если поток, выполняющий выражение, обращение к которому производится, не тот поток, который выполнил его инициализацию, поведение является определённым реализацией. Все объекты, объявленные _Thread_local(до C23)thread_local(с C23) имеют такую длительность хранения.
(с C11)
  • выделенное длительность хранения. Хранение выделяется и освобождается по запросу с помощью функций динамического выделения памяти.

Связь

Связь относится к возможности ссылки на идентификатор (переменную или функцию) в других областях видимости. Если переменная или функция с тем же идентификатором объявлены в нескольких областях видимости, но не могут быть обработаны из всех них, то генерируются несколько экземпляров переменной. Признаются следующие виды связей:

  • без связи. К идентификатору можно обратиться только из области, в которой он объявлен. Все параметры функций и все переменные в области блока, не объявленные как extern (включая объявленные как static), имеют такую связь.
    • внутренняя связь. К идентификатору можно обратиться из всех областей видимости в текущей единице трансляции. Все идентификаторы в области файла, объявленные как static (функции и переменные), имеют такую связь.
    • внешняя связь. К идентификатору можно обратиться из любой другой единицы трансляции во всей программе. Все функции, не объявленные как static, все переменные, объявленные как extern (если ранее не объявлены как static), и все нестатические переменные в области файла имеют такую связь.

Если один и тот же идентификатор появляется с внутренней и внешней связью в одной единице трансляции, поведение является неопределённым. Это возможно при использовании временных определений.

Связь и библиотеки

Декларации с внешней связью обычно размещаются в заголовочных файлах, чтобы все единицы трансляции, которые #include файл, могли ссылаться на один и тот же идентификатор, определённый где-то ещё.

Любая декларация с внутренней связью, которая появляется в заголовочном файле, приводит к созданию отдельного и отличного объекта в каждой единице трансляции, которая включает этот файл.

class="t-rev-begin">

Интерфейс библиотеки, заголовочный файл "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

Примечания

class="t-rev-begin">

Ключевое слово _Thread_local обычно используется через макрос thread_local, определённый в заголовочном файле <threads.h>.

(до C23)

Метки typedef и constexpr(с C23) формально указаны как спецификаторы класса хранения в грамматике языка C, но не определяют хранение.

class="t-rev-begin">

Спецификатор 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:2023):
    • 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/w/c/language/storage_duration

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API