У каждой переменной есть класс хранения в C?
Наивно можно было бы подумать, потому что обычно auto
предполагается, когда ключевое слово класса хранения не указано.
Тем не менее, для переменных в области файла положить auto
перед ними выдает ошибку.
#include <stdio.h>
auto int x;
int main(void){
x = 7;
printf("x = %d", x);
}
Clang жалуется:
3:10: error: illegal storage class on file-scoped variable
auto int x;
декларирование x
без каких-либо ключевых слов класса хранения, и он компилирует:
#include <stdio.h>
int x;
int main(void){
x = 7;
printf("x = %d", x);
}
Теперь интересно какой класс хранения x
имеет в приведенном выше примере? У него есть имя?
3 ответа
Ключевые слова auto
, static
, extern
, register
, а также _Thread_local
в стандарте упоминаются как спецификаторы класса хранения, но "объекты" (это стандартный термин для того, что мы обычно называем "переменными") не имеют классов хранения. Вместо этого у них есть связь (внешняя, внутренняя, нет) и продолжительность хранения (статическая, автоматическая, потоковая). Кроме того, любое объявление объекта может быть или не быть определением. Спецификаторы класса хранения вместе с областью, в которой объект объявлен, и с наличием у него инициализатора (int foo
против int foo = 3
), контролировать эти свойства. Проще всего показать, как это работает с таблицей:
sc-specifier scope initialized linkage storage duration is a definition
------------ ----- ----------- ------- ---------------- ---------------
auto file no [constraint violation]
auto file yes [constraint violation]
auto block no none automatic yes
auto block yes none automatic yes
none file no external static yes
none file yes external static yes
none block no none automatic yes
none block yes none automatic yes
static file no internal static yes
static file yes internal static yes
static block no none static yes
static block yes none static yes
extern file no external static no
extern file yes external static yes
extern block no external static no
extern block yes external static yes
Термин "спецификатор класса хранения" намеренно отличается от терминов "продолжительность хранения" и "связь", чтобы напомнить вам, что спецификаторы не дают вам независимого контроля над продолжительностью хранения и связью.
Язык не дает вам независимого контроля над продолжительностью хранения, связью и определением, потому что недоступные комбинации не имеют смысла. Длительность автоматического хранения имеет смысл только для переменных, объявленных в области видимости блока, а отсутствие определения имеет смысл только для переменных с внешней связью (поскольку только они могут быть определены в другом файле) и т. Д.
Я ушел register
а также _Thread_local
вне стола, потому что они особенные. register
это как auto
кроме того, что это также означает, что вам не разрешено брать адрес объекта. _Thread_local
делает продолжительность хранения переменной "потоком" и не меняет связь; он может быть использован сам по себе или с extern
или же static
, но это нарушение ограничения, чтобы объединить это с "авто". Я не уверен, что он делает, если вы используете его в объеме блока самостоятельно.
Из стандарта C § 6.2.4 параграф 3:
Объект, идентификатор которого объявлен без спецификатора класса хранения _Thread_local, а также с внешней или внутренней связью или со статическим спецификатором класса хранения, имеет статическую продолжительность хранения. Его время жизни - это полное выполнение программы, а его сохраненное значение инициализируется только один раз, до запуска программы.
Акцент мой. Обратная ссылка § 6.2.2 параграф 5:
Если объявление идентификатора для функции не имеет спецификатора класса хранения, его связь определяется точно так, как если бы он был объявлен с помощью спецификатора класса хранения extern. Если объявление идентификатора для объекта имеет область действия файла и не имеет спецификатора класса хранения, его связь является внешней.
Акцент мой снова.
Таким образом, глобальные переменные имеют статическую длительность хранения по умолчанию. Даже без стандарта, гарантирующего это, это единственный тип продолжительности хранения, который имеет смысл для глобальных переменных.
У каждой переменной есть класс хранения в C?
Да, хотя стандарт фактически использует термин "продолжительность хранения" для этого. Это то же самое, и стандарт также несколько непоследовательно использует термин "спецификатор класса хранения" для ключевых слов. auto
, static
, так далее..
Наивно можно подумать, что это так, потому что обычно предполагается, что auto используется, когда ключевое слово класса хранения не указано.
Абсолютно нет. По умолчанию extern
для функций и для всего, объявленного в области видимости файла. Только идентификаторы для объектов, объявленных в области видимости блока, по умолчанию auto
,
Тем не менее, для переменных в файловой области установка auto перед ними дает ошибку.
Как это должно. Стандарт прямо указывает, что
Спецификаторы класса хранения
auto
а такжеregister
не должны появляться в спецификаторах декларации во внешней декларации.
[C11, пункт 6.9/2]
Объявление x без ключевого слова класса хранения, и оно компилируется [....]
Конечно.
Теперь мне интересно, что класс хранения х имеет в приведенном выше примере? У него есть имя?
Его класс хранения соответствует ключевому слову extern
, Как я уже сказал, это значение по умолчанию для объявлений области файла. Но хотя стандарт использует терминологию "спецификатор класса хранения", опять же, он не использует "класс хранения" как отдельную концепцию. Это говорит вместо продолжительности хранения. Все переменные с внешними или внутренними связями имеют статическую длительность хранения, то есть они существуют на протяжении всей жизни программы.