Как определяется приоритет в указателях C?

14

Я натолкнулся на две декларации указателей, которые мне трудно понять. Мое понимание правил приоритета выглядит примерно так:

Operator             Precedence             Associativity
(), [ ]                  1                  Left to Right
*, identifier            2                  Right to Left
Data type                3

Но даже учитывая это, я не могу понять, как правильно оценить следующие примеры:

Первый пример

float * (* (*ptr)(int))(double **,char c)

Моя оценка:

  1. *(ptr)
  2. (int)
  3. *(*ptr)(int)
  4. *(*(*ptr)(int))

Потом,

  1. double **
  2. char c

Второй пример

unsigned **( * (*ptr) [5] ) (char const *,int *)
  1. *(ptr)
  2. [5]
  3. *(*ptr)[5]
  4. *(*(*ptr)[5])
  5. **(*(*ptr)[5])

Как я должен их читать?

trapaank
источник
1
Спрашивать о том, как язык обрабатывает свои особенности, здесь актуально.

Ответы:

7

Я предпочитаю первое : ptr - это указатель на функцию, которая принимает в качестве параметра int и возвращает указатель на функцию, которая принимает в качестве параметров указатель на указатель на double и символ и возвращает указатель на float.

Интерпретация :

(* PTR) (целое)

говорит, что ptr - это указатель на функцию, принимающую int в качестве аргумента. Чтобы узнать, что возвращает эта функция, нам нужно расширить наше представление:

(* (* ptr) (int))

это означает, что функция возвращает указатель на другую функцию. Параметры этой другой функции:

(двойной **, символ с)

и он возвращается

плавать *

И для второго : ptr - это указатель на массив из пяти указателей на функции, которые принимают в качестве параметров постоянный указатель на char и указатель на int, возвращая указатель на указатель на unsigned int.

Интерпретация :

(* (* ptr) [5])

объявляет ptr как указатель на массив из пяти указателей на функцию, принимающую

(char const *, int *)

в качестве аргументов и возвращения

без знака **

Даниэль Скокко
источник
7

Вы можете попробовать «Спираль по часовой стрелке», чтобы понять эти безумные заявления:

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

Я тоже писал об этом здесь:

http://www.kalekold.net/index.php?post=4

Гари Уиллоуби
источник
Спасибо за ответ. Но в методе Спираль по часовой стрелке, с чего начать в моем случае? В приведенных по ссылке примерах приведены простые примеры. Я не могу сопоставить свое уравнение с этим методом.
трапаанк
1
Вы должны начать с вашего идентификатора: ptr. у вас будет: «ptr - указатель на функцию, которая принимает int и возвращает указатель на функцию, которая принимает указатель на указатель на double и символ и возвращает указатель на число с плавающей точкой». попробуйте spyral, и вы получите то же самое.
Remo.D
1

Это указатель на функцию. Человек, который написал это, мог бы лучше использовать typedefs, чтобы сделать его более понятным.

По сути это указатель на функцию с этими параметрами. float * myfunc (double **, char)

Майкл Шоу
источник
4
Я держу пари, что человек, который написал это, является учителем.
Mouviciel
Будем надеяться, что это не учитель, потому что вам не нужно знать, как это дерьмо. Хотя я полагаю, что хороший учитель сначала ударил бы вас по лицу такими выражениями, позволяя вам почесать голову, пытаясь их интерпретировать, а затем показал бы вам, как правильно использовать typedef.
1

Используя cdecl.org:

char * const (* (* const bar) [5]) (int)

объявить bar как константный указатель на массив 5 указателя на функцию (int), возвращающий константный указатель на символ

без знака ** (* (* ptr) [5]) (char const *, int *)

объявить ptr как указатель на массив 5 указателя на функцию (указатель на const char, указатель на int), возвращающий указатель на указатель на unsigned

Мартин Йорк
источник