Комплексные декларации
Как интерпретировать сложные объявления, например:
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".
Ответ 5
Хотя уже был дан ответ, но вы также можете прочитать эту статью:
http://unixwiz.net/techtips/reading-cdecl.html
Ответ 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