Выбрать главу

R.7.1 Спецификации

В описании можно использовать следующие спецификации:

спецификация-описания:

 спецификация-класса-памяти

 спецификация-типа

 спецификация-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; // ошибка: второе определение

static int b; // `b' имеет внутреннее связывание

extern int b; // `b' все еще внутреннее

int c; // `c' имеет внешнее связывание

static int c; // ошибка: противоречие в связывании

extern int d; // `d' имеет внешнее связывание

static int d; // ошибка: противоречие в связывании

Имя неопределенного класса можно использовать в описании extern. Однако, такое описание нельзя использовать прежде, чем класс будет определен, например,

struct S;

extern S a;

extern S f();

extern void g(S);

void h()

{