Вывод C объявлений, таких как: double (* b)

Я пытаюсь выяснить некоторые C-декларации. В чем смысл этих С-деклараций?

double (*b)[n]; double (*c[n])(); double (*d())[n]; 

 double (*b)[n]; 

b – указатель на массив из n удвоений

 double (*c[n])(); 

c – массив из n указателей на функции, принимающие неопределенное количество аргументов и возвращающих двойные

 double (*d())[n]; 

d – функция, принимающая неопределенное число аргументов и возвращающая указатель на массив из n удвоений

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

  double (*d())[n]; 

что первое, что делается с d? Он вызывается с помощью (), поэтому это функция, которая принимает неопределенное количество аргументов и возвращает … что сработало с результатом? Он разыменован (*), поэтому он является указателем на . Затем результат индексируется, поэтому он представляет собой массив n … что осталось? двойной, поэтому из двухместных . Читая части, выделенные жирным шрифтом, вы получите ответ.

Давайте посмотрим другой пример

  void (*(*f)(int)[n])(char) 

Здесь f сначала разыменовывается, поэтому он является указателем на … он затем вызывается с (int), поэтому функция принимает int и возвращает , результат затем индексируется с помощью [n], поэтому массив из n . Результат разыменовывается снова, поэтому указывает на . Тогда результат вызывается (char), поэтому функции, принимающие char и возвращающие (все оставлены недействительными) void . Таким образом, f является указателем на функцию, принимающую int и возвращающую массив из n указателей на функции, принимающие char и возвращающие void .

НТН

Основное правило для синтаксического анализа деклараций C «читается справа налево, а изнутри выпрыгивает вправо, оставляя пару круглых скобок», т.е. начинаем самую глубоко вложенную пару круглых скобок, а затем начинаем искать вправо. Технически вы должны знать ассоциативность операторов, но она работает достаточно хорошо в большинстве ситуаций.

Теперь примените это (упрощенное) правило к вашему вопросу:


 double (*b)[n]; ^ 

b –

 double (*b)[n]; ^ 

указатель на

 double (*b)[n]; ^^^ 

и массив

 double (*b)[n]; ^^^^^^ 

двойников.


 double (*c[n])(); ^^^^ 

c – массив

 double (*c[n])(); ^ 

указатели на

 double (*c[n])(); ^^ 

функции

 double (*c[n])(); ^^^^^^ 

возrotation двойным.


 double (*d())[n]; ^^^ 

d – функция

 double (*d())[n]; ^ 

возвращая указатель на

 double (*d())[n]; ^^^ 

массив

 double (*d())[n]; ^^^^^^ 

двойники


Существует чистая утилита, найденная на большинстве * nixes, называемая cdecl , которая берет строку декларации C и превращает ее в предложение естественного языка.

Попробуйте этот путь.

во-первых, вы должны быть знакомы с этими тремя символами:

  1. * - указатель.
 2. [] - массив.
 3. () - функция. (Извещение: не круглые скобки) 

в качестве примера возьмем «double (* d ()) [n]».

первый шаг – найти идентификатор в объявлении, идентификатор – это имя переменной, здесь это «d».

  (я)
 - что такое «d»?
 -------------------------------------------------- ----------------------
 посмотрите на правую часть идентификатора, чтобы увидеть, есть ли «[]» или «()»:
 ... d [] ...: d - массив.
 ... d () ...: d - функция.

 если нет, посмотрите на левую сторону, чтобы увидеть, есть ли «*»:
 ... * d ...: d - указатель.
 -------------------------------------------------- ---------------------- 

теперь мы обнаружили, что d является функцией. используйте x для замены d (), тогда объявление становится «double (* x) [n]»

  (II)
 - что такое «х»?
 -------------------------------------------------- ----------------------
 repeat (i), мы находим, что x является указателем.
 это означает, что d - это функция, возвращающая указатель.
 -------------------------------------------------- ---------------------- 

используйте y для замены * x, тогда объявление становится «double y [n]»

  (III)
 - что такое «у»?
 -------------------------------------------------- ----------------------
 repeat (i), мы находим, что y является массивом из n элементов.
 это означает, что d - это функция, возвращающая указатель на массив из n элементов.
 -------------------------------------------------- ---------------------- 

используйте z для замены y [n], тогда объявление становится «double z»,

  (IV)
 - Что такое «z»?
 -------------------------------------------------- ----------------------
 Повторяем (i), получаем, что z является двойным.
 это означает, что d - это функция, возвращающая указатель на массив из n двойных элементов.
 -------------------------------------------------- ---------------------- 

давайте посмотрим другое выражение:

  void (* (* f) (int) [n]) (char) 
  1.
   мы найдем f.
 2.
   f - указатель.  * f -> a
   void (* a (int) [n]) (char)
 3.
   a - функция.  a () -> b
   void (* b [n]) (char)
   -f - указатель на функцию (с параметром int) -
 4.
   b - массив.  b [] -> c
   void (* c) (char)
   -f - указатель на функцию, возвращающую массив (из n элементов) -
 5.
   c - указатель.  * c -> d
   void d (char)
   -f - указатель на функцию, возвращающую массив из n указателей -
 6.
   d - функция, возвращающая пустоту.
   -f - указатель на функцию, возвращающую массив из n указателей на функции (с параметром char), возвращающий void - 

Есть два больших ресурса для понимания «C gibberish»:

  • http://cdecl.org/ – Онлайн-сервис, который переводит «C gibberish ↔ English»
  • «По часовой стрелке / спиральное правило» Дэвида Андерсона, если вы хотите понять, что лучше, что происходит

Вывод cdecl.org:

  • double (*c[n])() : Синтаксическая ошибка ( n здесь недействительна)
  • double (*c[])() : объявить c как массив указателя на функцию, возвращающую double