Комплексные декларации

Как интерпретировать сложные объявления, например:

int * (* (*fp1) (int) ) [10]; ---> declaration 1
int *( *( *[5])())(); --------> declaration 2

Есть ли какое-либо правило, которое следует соблюдать, чтобы понять приведенные выше объявления?

Ответ 1

Вот отличная статья о том, как читать сложные объявления в C: http://www.codeproject.com/KB/cpp/complex_declarations.aspx

Это очень помогло мне!

В частности - вы должны прочитать раздел "Правильное правило". Здесь цитата:

int * (* (* fp1) (int)) [10]; Это можно интерпретировать следующим образом:

  • Начать с имени переменной -------------------------- fp1
  • Ничего правильного, но), так что идите влево, чтобы найти * -------------- - указатель
  • Выскочите из круглых скобок и встретитесь (int) --------- с функция, которая принимает int как аргумент
  • Идите влево, найдите * ---------------------------------------- и верните указатель
  • Скопируйте скобки в скобки, идите направо и нажмите [10] -------- на массив 10
  • Идите влево, найдите * ----------------------------------------- указатели на
  • Идите влево, найдите int -------------------------------- ints.

Ответ 2

Вы можете использовать cdecl *:

cdecl> explain int *( *( *a[5])())();
 declare a as array 5 of pointer to function
 returning pointer to function returning pointer to int
cdecl> explain int * (* (*fp1) (int) ) [10];
 declare fp1 as pointer to function (int) returning
 pointer to array 10 of pointer to int

* Связанный - это веб-сайт, который использует этот инструмент командной строки в бэкэнд.

Ответ 3

Я уже давно изучил следующий метод:

Начните с идентификатора типа (или внутренней скобки) и перемещайтесь по спирали, беря элемент справа вначале

В случае

 int * (* (*fp1) (int) ) [10];

Вы можете сказать:

  • fp1 - (ничего справа не перемещается влево)
  • указатель на (перемещение из внутренней скобки
  • функция, принимающая int as agument (первая справа)
  • и возвращает указатель на (выход из скобки)
  • массив из 10 элементов типа
  • указатель на (ничего не осталось справа)
  • int

Результат:

fp1 является указателем на функцию, принимающую int и возвращающую указатель на массив из 10 указателей на int

Рисунок фактической спирали (в вашем уме, по крайней мере) помогает много.

Ответ 4

Для решения этих сложных заявлений необходимо иметь в виду правило, что приоритет функции-вызова operator() и оператора индекса массива [] выше, чем оператор разыменования *. Очевидно, скобка() может использоваться для переопределения этих приоритетов.

Теперь выполните свое объявление из середины, что означает имя идентификатора.

int * (* (* fp1) (int)) [10]; --- > декларация 1

В соответствии с приведенным выше правилом приоритетов вы можете легко понять это, разбив декларацию как

fp1 * (int) * [10] * int

и читайте его прямо слева направо на английском языке как "fp1 - это указатель на функцию, принимающую int и возвращающую указатель на массив [10] указателей на int". Обратите внимание, что объявление разбивается таким образом, чтобы понять его вручную. Компилятору не нужно анализировать его таким образом.

Аналогично,

int * (* (* [5])())(); -------- > Объявление 2

нарушается как

[5] *() *() * int

Итак, он объявляет "массив [5] указателей типа функции(), который возвращает указатель на функцию(), которая, в свою очередь, возвращает указатель на int".

Ответ 6

Начните с самого левого идентификатора и проведите свой путь, вспомнив, что отсутствовала какая-либо явная группировка [] и () bind перед *, например:

    *a[]                 -- is an array of pointer
  (*a)[]                 -- is a pointer to an array
    *f()                 -- is a function returning pointer
  (*f)()                 -- is a pointer to a function

Таким образом, мы читаем int *(*(*fp1)(int))[10] как:

         fp1                     -- fp1
        *fp1                     -- is a pointer
       (*fp1)(int)               -- to a function
                                      taking an int parameter
      *(*fp1)(int)               -- returning a pointer
     (*(*fp1)(int))[10]          -- to a 10-element array
    *(*(*fp1)(int))[10]          -- of pointer 
int *(*(*fp1)(int))[10]          -- to int

Объявление int *(*(*[5])())() представляет собой немного сложную задачу, поскольку нет идентификатора; вы обычно видите это в объявлениях функций, где параметр имеет такой тип:

void foo(int *(*(*[5])())(), double);

Это тот же принцип, что и неменованный int параметр в объявлении fp1. Массив дает нам ключ, вы также можете искать самую левую внутреннюю группировку круглых скобок.

                         -- unnamed
         [5]             -- is a 5-element array ([] binds before *)
        *[5]             -- of pointers
       (*[5])()          -- to functions
      *(*[5])()          -- returning pointers
     (*(*[5])())()       -- to functions
    *(*(*[5])())()       -- returning pointers
int *(*(*[5])())()       -- to int

Ответ 7

По часовой стрелке/спирали:

* http://c-faq.com/decl/spiral.anderson.html