На стадии компиляции производится полная идентификация типов всех входящих в программу выражений. Даже отсутствие имени типа в объявлении как, например,
unsigned long MMM; // Вместо имени типа - комбинация модификаторов unsigned long.
восстанавливается транслятором в соответствии с принятыми в C++ правилами умолчания.
Помимо явного объявления типа в C++ предусмотрены дополнительные средства описания имён типов. Таким средством является typedef-объявление. С его помощью в программу можно ввести новые имена, которые затем используются для обозначения производных и основных типов.
typedef-объявление - это инструмент объявления. Средство ввода новых имён в программу, средство замены громоздких последовательностей имён в объявлениях (но не определениях!) новыми именами.
Синтаксис typedef-объявления как подмножества объявления представляется внушительным списком форм Бэкуса-Наура. Но при известной степени концентрации это нагромождение БНФ всё же можно разобрать:
Объявление ::= [СписокСпецификаторовОбъявления][СписокОписателей]; СписокСпецификаторовОбъявления ::= СпецификаторОбъявления [СписокСпецификаторовОбъявления] СпецификаторОбъявления ::= typedef ::= ***** СписокОписателей ::= [СписокОписателей,] ОписательИнициализатор ОписательИнициализатор ::= Описатель [Инициализатор] Описатель ::= dИмя ::= ***** dИмя ::= Имя ::= ОписанноеИмяТипа ::= ***** ОписанноеИмяТипа ::= Идентификатор СписокСпецификаторовТипа ::= СпецификаторТипа [СписокСпецификаторовТипа] СпецификаторТипа ::= ИмяПростогоТипа ::= СпецификаторКласса ::= *****
Таким образом, typedef-объявление является объявлением, которое начинается спецификатором typedef и состоит из последовательностей разнообразных спецификаторов объявления и описателей. Список описателей (элементы списка разделяются запятыми) может содержать языковые конструкции разнообразной конфигурации. В него могут входить описатели (в конце концов, это всего лишь разнообразные имена) с символами ptrОпераций (* и &), описатели, заключённые в круглые скобки, описатели в сопровождении заключённых в скобки списков объявлений параметров, описателей const и volatile, а также заключённых в квадратные скобки константных выражений (последние, надо полагать, предназначены для спецификации массивов).
В качестве примера рассмотрим, следующее typedef-объявление:
typedef int Step, *pInteger;
Это объявление начинается спецификатором typedef, содержит спецификатор объявления int и список описателей, в который входит два элемента: имя Step и имя pInteger, перед которым стоит символ ptrОперации *.
Объявление эквивалентно паре typedef-объявлений следующего вида:
typedef int Step; typedef int *pInteger;
В соответствии с typedef-объявлениями, транслятор производит серию подстановок, суть которых становится понятной из анализа примера, в котором пара операторов объявления
Step StepVal; extern pInteger pVal;
заменяется следующими объявлениями:
int StepVal; extern int * pVal;
На основе этого примера можно попытаться воспроизвести алгоритм подстановки:
Если в программе присутствует typedef-объявление
typedef char* (*PPFF) (int,int,int*,float);
то компактное объявление функции
PPFF ReturnerF(int, int);
преобразуется при трансляции в сложное, но как мы далее увидим, абсолютно корректное объявление:
char* (*ReturnerF(int, int))(int,int,int*,float);
При этом по идентификатору PPFF в прототипе функции находится контекст замены char* (*PPFF) (int,int,int*,float), в котором замещаемый описатель PPFF заменяется замещающим описателем ReturnerF(int, int).
Цель достигнута. Простое становится сложным. И как хорошо, что всё это происходит без нашего участия! Перед нами очередное средство для "облегчения" труда программиста.
Заметим, что подстановка возможна и в том случае, когда замещаемый описатель заменяется пустым замещающим описателем.
То же самое typedef-объявление позволяет построить следующее объявление функции:
void MyFun (int, int, int*, float, PPFF);
Рассмотрим ещё один пример.
typedef long double NewType; /* Используем спецификатор для ввода в программу нового имени типа. */ ::::: NewType MyFloatVal;
Новое имя для обозначения типа введено…
Новое имя ранее уже поименованного типа называют ОПИСАННЫМ ИМЕНЕМ ТИПА. Именно таким образом и назывался (так выглядел) соответствующий нетерминальный символ во множестве БНФ, связанных с typedef-объявлением.
Описанное имя типа может заменять прежнее имя типа везде, где это возможно, поскольку объявления с описанным именем при трансляции заменяется первоначальным объявлением:
long double MyFloatVal;
В ряде случаев описанное имя типа может оказаться единственным именем для обозначения безымянного типа (об этом позже).
В области действия объявления имени типа (typedef-объявления), идентификатор NewType (он является спецификатором типа) становится синонимом другого спецификатора типа - конструкции long double. Иногда подобным образом вводимый синоним называют замещающим идентификатором.
Использование спецификатора typedef подчиняется следующим правилам (ничто не даётся даром):
1. Спецификатор typedef может переопределять имя как имя типа, даже если это имя само уже было ранее введено typedef спецификатором:
typedef int I; typedef I I;
2. Спецификатор typedef не может переопределять имя типа, объявленное в одной и той же области действия, и замещающее имя другого типа.
typedef int I; typedef float I; // Ошибка: повторное описание…
3. На имена, введённые в программу с помощью спецификатора typedef, распространяются правила области действия, за исключением разрешения на многократное использование имени (правило 1.).
Назад | Содержание | Вперед