C Language Интерпретация деклараций

пример

Отличительной синтаксической особенностью C является то, что объявления отражают использование объявленного объекта, как это было бы в нормальном выражении.

Следующий набор операторов с одинаковым приоритетом и ассоциативностью повторно используется в деклараторах, а именно:

  • унарный * «разыменовать» оператор , который обозначает указатель;
  • бинарный [] «подписчик на массив», который обозначает массив;
  • оператор (1 + n) -ary () «вызов функции», который обозначает функцию;
  • () скобки группировки, которые переопределяют приоритет и ассоциативность остальных перечисленных операторов.

Вышеуказанные три оператора имеют следующий приоритет и ассоциативность:

оператор Относительный приоритет Ассоциативность
[] (подписка на массив) 1 Слева направо
() (вызов функции) 1 Слева направо
* (разыменование) 2 Справа налево

При интерпретации объявлений нужно начинать с идентификатора наружу и применять соседние операторы в правильном порядке в соответствии с приведенной выше таблицей. Каждое приложение оператора может быть заменено следующими английскими словами:

выражение интерпретация
thing[X] массив размера X ...
thing(t1, t2, t3) функция, принимающая t1 , t2 , t3 и возвращающая ...
*thing указатель на ...

Из этого следует, что начало английской интерпретации всегда начинается с идентификатора и заканчивается типом, который стоит в левой части объявления.

Примеры

char *names[20];

[] имеет приоритет над * , поэтому интерпретация: names - это массив размером 20 указателя на char .

char (*place)[10];

В случае использования скобок для переопределения приоритета сначала применяется * : place - это указатель на массив размером 10 char .

int fn(long, short);

Здесь нет приоритета: fn - это функция, выполняющая long , short и возвращающие int .

int *fn(void);

Сначала применяется функция () : fn - это функция, принимающая void и возвращающая указатель на int .

int (*fp)(void);

Переопределение приоритета () : fp является указателем на функцию, принимающую void и возвращающую int .

int arr[5][8];

Многомерные массивы не являются исключением из правила; операторы [] применяются в порядке слева направо в соответствии с ассоциативностью в таблице: arr представляет собой массив размером 5 массива размером 8 из int .

int **ptr;

Два оператора разыменования имеют одинаковый приоритет, поэтому ассоциативность вступает в силу. Операторы применяются в порядке справа налево: ptr является указателем на указатель на int .

Несколько объявлений

Запятая может использоваться как разделитель (* not *, действующий как оператор запятой), чтобы разграничить несколько деклараций внутри одного оператора. Следующий оператор содержит пять объявлений:
int fn(void), *ptr, (*fp)(int), arr[10][20], num;

Объявленные объекты в приведенном выше примере:

  • fn : функция, принимающая void и возвращающая int ;
  • ptr : указатель на int ;
  • fp : указатель на функцию, принимающую int и возвращающую int ;
  • arr : массив размера 10 массива размера 20 из int ;
  • num : int .

Альтернативная интерпретация

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

/*
 * Subscripting "arr" and dereferencing it yields a "char" result.
 * Particularly: *arr[5] is of type "char".
 */
char *arr[20];

/*
 * Calling "fn" yields an "int" result.
 * Particularly: fn('b') is of type "int".
 */
int fn(char);

/*
 * Dereferencing "fp" and then calling it yields an "int" result.
 * Particularly: (*fp)() is of type "int".
 */
int (*fp)(void);

/*
 * Subscripting "strings" twice and dereferencing it yields a "char" result.
 * Particularly: *strings[5][15] is of type "char"
 */
char *strings[10][20];