MyTetra Share
Делитесь знаниями!
Понимание и интерпретация сложных деклараторов в С и C++
Время создания: 02.02.2024 10:52
Текстовые метки: язык, C, Си, C++, Си++, понимание, интерпретация, расшифровка, декларация, описание, объявление, определение, тип, синтаксис, выражение
Раздел: Компьютер - Программирование - Язык C (Си)
Запись: xintrea/mytetra_syncro/master/base/1706860360unhuvex1em/text.html на raw.github.com

Сложный оператор объявления — это идентификатор для более чем одного модификатора массива, указателя или функции. К одному идентификатору можно применять различные сочетания модификаторов массива, указателя или функции. Обычно для упрощения объявлений можно использовать определения typedef. См. статью Объявления Typedef.

При интерпретации сложных деклараторов квадратные и круглые скобки (т. е., модификаторы справа от идентификатора) имеют приоритет над звездочками (т. е., модификаторами слева от идентификатора). Квадратные и круглые скобки имеют одинаковый приоритет и задают связывание слева направо. После полной интерпретации декларатора на последнем шаге производится применение спецификатора типа. С помощью круглых скобок можно переопределить порядок связи по умолчанию и принудительно задать определенную интерпретацию. Однако не допускается использование скобок непосредственно вокруг имени идентификатора. Это может быть ошибочно истолковано как список параметров.

Простым способом интерпретации сложных деклараторов является чтение "изнутри наружу", с помощью следующих 4 шагов:


  1. Начните с идентификатора и найдите ближайшие квадратные или круглые скобки справа от него (если есть).
  2. Интерпретируйте эти квадратные или круглые скобки, затем найдите звездочку слева.
  3. Если на каком-либо шаге обнаружится правая круглая скобка, перейдите назад и примените правила 1 и 2 ко всему выражению в круглых скобках.
  4. Примените спецификатор типа.


Вот пример сложного выражения:


char *( *(*var)() )[10];

^ ^ ^ ^ ^ ^ ^

7 6 4 2 1 3 5


В этом примере шаги пронумерованы по порядку и интерпретируются следующим образом:


  1. Идентификатор var объявлен как
  2. указатель на
  3. функцию, возвращающую
  4. указатель на
  5. массив из 10 элементов, которые являются
  6. указателями на
  7. значения типа char.


Примеры

В следующих примерах приведены другие сложные объявления и показано, как круглые скобки могут влиять на значение объявления.


// var - это массив из указателей на значения int

int *var[5];


Модификатор массива имеет более высокий приоритет, чем модификатор указателя, поэтому переменная var объявляется как массив. Модификатор указателя применяется к типу элементов массива; следовательно, элементы массива являются указателями на значения int.


// var - это указатель на массив из int-значений

int (*var)[5];


В этом объявлении переменной var скобки обеспечивают модификатору указателя более высокий приоритет, чем у модификатора массива, и переменная var объявляется как указатель на массив из 5 значений int.


// var - это функция, возвращающая указатель на значение long

long *var( long, long );


Модификаторы функции также имеют более высокий приоритет, чем модификаторы указателя, поэтому в этом объявлении var переменная var объявляется как функция, возвращающая указатель на значение типа long . В соответствии с объявлением функция принимает два значения типа long в качестве аргументов.


// var - это указатель на функцию, возвращающую значение long

long (*var)( long, long );


Этот пример аналогичен предыдущему. Скобки отдают модификатору указателя более высокий приоритет, чем у модификатора функции, и переменная var объявляется как указатель на функцию, возвращающую значение типа long . Как и ранее, эта функция принимает два аргумента типа long .


struct both /* Array of pointers to functions */

{ /* returning structures */

int a;

char b;

} ( *var[5] )( struct both, struct both );


Элементы массива не могут быть функциями, но это объявление показывает, как объявить массив указателей на функции. В данном примере переменная var объявляется как массив из 5 указателей на функции, возвращающие структуры с двумя членами. В качестве аргументов для функций объявлены две структуры с тем же типом структуры, both. Обратите внимание, что скобки вокруг *var[5] обязательны. Без них объявление было бы недопустимой попыткой объявить массив функций, как показано ниже:

// Ошибка

struct both *var[5](struct both, struct both);


Следующий оператор объявляет массив указателей.


unsigned int *(* const *name[5][10] ) ( void );


Массив name содержит 50 элементов, организованных в многомерный массив. Элементы являются указателями на указатель, представляющий собой константу. Этот постоянный указатель указывает на функцию, которая не имеет параметров и возвращает указатель на тип без знака.

В следующем примере показана функция, возвращающая указатель на массив из трех значений типа double .


double ( *var( double (*)[3] ) )[3];


В этом объявлении функция возвращает указатель на массив, поскольку функции не могут возвращать массивы. Здесь переменная var объявлена как функция, возвращающая указатель на массив из трех значений типа double . Функция var принимает один аргумент. Аргумент, как и возвращаемое значение, является указателем на массив из трех значений типа double . Тип аргумента задан сложным абстрактным декларатором abstract-declarator. Скобки вокруг звездочки в типе аргумента обязательны. Без них аргумент будет иметь тип массива из трех указателей на значения типа double . Обсуждение и примеры абстрактных деклараторов см. в статье Абстрактные деклараторы.


union sign /* Array of arrays of pointers */

{ /* to pointers to unions */

int x;

unsigned y;

} **var[5][5];


Как показано в приведенном выше примере, указатель может указывать на другой указатель, и массив может содержать элементы, являющиеся массивами. Здесь переменная var представляет собой массив из 5 элементов. Каждый элемент представляет собой 5-элементный массив указателей на объединения с двумя членами.


union sign *(*var[5])[5]; /* Array of pointers to arrays

of pointers to unions */


В этом примере показано, как круглые скобки изменяют значение объявления. В этом примере переменная var является 5-элементным массивом указателей на 5-элементные массивы указателей на объединения.


Так же в этом разделе:
 
MyTetra Share v.0.65
Яндекс индекс цитирования