описания:
спецификации-описания optсписок-описателей opt;
описание-asm
определение-функции
спецификация-связи
Описатели в списке-описателей (§R.8) содержат описываемые идентификаторы. Конструкция спецификации-описания может отсутствовать только в определении функций (§R.8.3) или в описании функций. Список-описателей может быть пустым, только при описании класса (§R.9) или перечисления (§R.7.2), т.е. когда спецификация-описания есть спецификация-класса или спецификация-перечисления. Конструкция описание-asm объясняется в §R.7.3, а спецификация-связи в §R.7.4. Описание происходит в определенной области видимости (§R.3.2), правила области видимости приводятся в §R.10.4.
В описании можно использовать следующие спецификации:
спецификация-описания:
спецификация-класса-памяти
спецификация-типа
спецификация-fct
спецификация-шаблона-типа
friend
typedef
спецификации-описания:
спецификации-описания optспецификация-описания
Самая длинная последовательность конструкций спецификация-описания, которая, возможно, является именем типа, образует в описании конструкцию спецификации-описания. Последовательность должна быть согласованной, что объясняется ниже. Например,
typedef char* Pc;
static Pc; // ошибка: нет имени
Здесь описание static Pc является незаконным, поскольку не указано никакого имени статической переменной типа Pc. Чтобы иметь переменную типа int с именем Pc, необходимо задать спецификацию-типа int, чтобы показать, что (пере)определяется имя Pc из typedef, а не просто Pc является одним из элементов последовательности конструкций спецификация-описания, например,
void f(const Pc); // void f(char* const)
void g(const int Pc); // void g(const int)
Укажем, что поскольку signed, unsigned, long и short по умолчанию трактуются как int, конструкция имя-typedef, которая появляется после одной из перечисленных спецификаций типа, должна задавать (пере)определяемое имя, например,
void h(unsigned Pc); // void h(unsigned int)
void k(unsigned int Pc); // void k(unsigned int)
R.7.1.1 Спецификации класса памяти
Спецификации класса памяти могут быть такие:
спецификация-класса-памяти:
auto
register
static
extern
Спецификации auto и register могут применяться только для имен объектов, которые описаны в блоке (§R.6.3), или для формальных параметров (§R.8.3). Почти всегда спецификация auto избыточна и используется не часто, так, auto используется, чтобы явно отделить оператор-описание от оператора-выражения (§R.6.2).
Описание register является описанием auto, которое подсказывает транслятору, что описываемые переменные будут использоваться достаточно интенсивно. Подсказка может быть проигнорирована, и во многих реализациях она игнорируется в том случае, когда берется адрес переменной.
Описание объекта считается определением, если только оно не содержит спецификации extern и инициализации (§R.3.1).
Определение приводит к выделению памяти соответствующего размера и выполнению соответствующей инициализации (§R.8.4).
Спецификации static и extern могут применяться только к именам объектов или функций или к анонимным объединениям. Внутри блока недопустимы описания функций со спецификацией static или формальных параметров со спецификацией static или extern. Статические члены класса описываются в §R.9.4. Спецификация extern недопустима для членов класса.
Имя со спецификацией static подлежит внутреннему связыванию. Объекты, описанные как const, подлежат внутреннему связыванию, если только они не были описаны с внешней связью. Имя со спецификацией extern подлежит внешнему связыванию, если только ранее оно не было описано с внутренней связью. Имя с файловой областью видимости и без спецификации-класса-памяти подлежит внешнему связыванию, если только ранее оно не было описано с внутренней связью или со спецификацией const. В смысле связывания для функций, не являющихся членами, спецификация inline эквивалентна static (§R.3.3). Для одного имени все его спецификации, определяющие связывание, должны быть согласованы. Например,
static char* f(); // f() имеет внутреннее связывание
char* f() // f() все еще внутреннее
{/*… */}
char* g(); // g() имеет внешнее связывание
static char* g() // ошибка: противоречие в связывании
{/*… */}
static int a; // `a' имеет внутреннее связывание
int a; // ошибка: второе определение
Читать дальше