У каждой переменной есть класс хранения в 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, Как я уже сказал, это значение по умолчанию для объявлений области файла. Но хотя стандарт использует терминологию "спецификатор класса хранения", опять же, он не использует "класс хранения" как отдельную концепцию. Это говорит вместо продолжительности хранения. Все переменные с внешними или внутренними связями имеют статическую длительность хранения, то есть они существуют на протяжении всей жизни программы.

Другие вопросы по тегам