Подтвердить что ты не робот

Сложная декларация C

Я просто просматривал какой-то код в Интернете и нашел это:

float * (*(*foo())[SIZE][SIZE])()

Как мне прочитать это объявление? Существует ли определенный набор правил для чтения таких сложных объявлений?

4b9b3361

Ответ 1

Я не сделал этого через некоторое время!

Начните с foo и идите направо.

float * (*(* <суб > foo()суб > )[SIZE][SIZE])()

foo - это функция без аргументов...

Не может идти правильно, так как есть закрывающая скобка. Идите влево:

float * (*( <суб > * foo()суб > )[SIZE][SIZE])()

foo - это функция без аргументов, возвращающая указатель

Нельзя идти дальше, так что давайте пересечь круглые скобки и снова идем вправо

float * (* <суб > (* foo())суб > [SIZE][SIZE])() float * (* <суб > (* foo())[SIZE]суб > [SIZE])() float * (* <суб > (* foo())[SIZE][SIZE]суб > )()

foo - это функция без аргументов, возвращающая указатель на массив массивов SIZE из SIZE...

Достигнутая закрывающая скобка, снова оставлена ​​для достижения символа указателя:

float * ( <суб > *(* foo())[SIZE][SIZE]суб > )()

foo - это функция без аргументов, возвращающая указатель на массив массивов SIZE указателей SIZE для...

Левая скобка снова, поэтому мы пересекаем ее и снова идем вправо:

float * <суб > ( *(* foo())[SIZE][SIZE])суб > () float * <суб > ( *(* foo())[SIZE][SIZE])()суб >

foo - это функция без аргументов, возвращающая указатель на массив массивов SIZE указателей SIZE на функцию без аргументов...

И осталось до конца

<суб > float * ( *(* foo())[SIZE][SIZE])()суб >

foo - это функция без аргументов, возвращающая указатель на массив массивов SIZE указателей SIZE на функцию без аргументов, возвращающую указатель на float


И кто бы ни написал это, пожалуйста, научите его использовать typedef:

// Function that returns a pointer to float
typedef float* PFloatFunc ();

// Array of pointers to PFloatFunc functions
typedef PFloatFunc* PFloatFuncArray2D[SIZE][SIZE];

// Function that returns a pointer to a PFloatFuncArray2D
PFloatFuncArray2D* foo();

Ответ 2

Стандартное правило: найдите самый левый идентификатор и проведите свой путь, вспомнив, что [] и () связывают до *:

            foo                      -- foo
            foo()                    -- is a function
           *foo()                    -- returning a pointer
          (*foo())[SIZE]             -- to a SIZE-element array
          (*foo())[SIZE][SIZE]       -- of SIZE-element arrays
         *(*foo())[SIZE][SIZE]       -- of pointers
        (*(*foo())[SIZE][SIZE])()    -- to functions
      * (*(*foo())[SIZE][SIZE])()    -- returning pointers
float * (*(*foo())[SIZE][SIZE])();   -- to float

Итак, представьте, что у вас есть куча функций, возвращающих указатели на float:

float *quux();
float *bar();
float *bletch();
float *blurga();

Скажем, вы хотите сохранить их в таблице 2x2:

float *(*tab[SIZE][SIZE])() = {quux, bar, bletch, blurga};

tab представляет собой массив SIZE x SIZE указателей на функции, возвращающие указатели на float.

Теперь давайте решим, что мы хотим, чтобы функция возвращала указатель на эту таблицу:

float *(*(*foo())[SIZE][SIZE])()
{
  static float *(*tab[SIZE][SIZE])() = {quux, bar, bletch, blurga};
  return &tab;
}

Обратите внимание, что у вас может быть несколько функций, которые строят таблицы разных функций или организуют одни и те же функции по-разному:

float *(*(*qwerbl())[SIZE][SIZE])()
{
  static float *(*tab[SIZE][SIZE])() = {blurga, bletch, bar, quux};
  return tab;
}

что является единственной причиной, по которой я могу придумать что-то подобное. Вы не должны часто видеть подобные типы в дикой природе (хотя иногда они возникают, и я был виновен в написании чего-то подобного ужасного).

Ответ 3

Согласно cdecl.org

объявить foo как функцию, возвращающую указатель на массив SIZE массива SIZE указателя на функцию, возвращающую указатель на float

Используйте правило спирали, данное Luchian Grigore, если вы хотите его декодировать вручную.

Ответ 4

Лучшее, что можно сделать здесь, это преобразовать в серию typedefs.

typedef float * fnReturningPointerToFloat();
typedef fnReturningPointerToFloat* fnArray[SIZE][SIZE];
fnArray* foo();

Ответ 5

Как правило, вы можете попробовать cdecl.org, но вам нужно заменить SIZE

Скажите, что вы заменили SIZE на 12, вы получите:

объявить foo как функцию, возвращающую указатель на массив 12 массива 12 из указатель на функцию, возвращающую указатель на float

Я не уверен, что это действительно помогает!

Два наблюдения здесь:

  • Я предполагаю, что у этого кода не было комментария рядом с ним, объясняя, в чем его цель (т.е. не техническое объяснение того, что это такое, а то, что он добивается с точки зрения функциональности/бизнеса). Если программист должны использовать что-то столь же сложное, как это, они должны быть достаточно хорошими, чтобы объяснить будущим сопровождающим, какой цели он служит.
  • Конечно, в С++ существуют более очевидные и, вероятно, более безопасные способы достижения одного и того же.

Ответ 6

Этот документ дает мне лучший ключ о том, как легко подготовить любое объявление C:

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

Существует три простых шага:

  • Начиная с неизвестного элемента, двигайтесь по спирали/по часовой стрелке; при замене следующих элементов замените их соответствующими английскими утверждениями:

    • [X] или [] = > Array X size of... или Array undefined размер...

    • (type1, type2) = > функция, передающая тип1 и возвращаемый тип2...

    • * = > указатель для...

  • Продолжайте делать это по спирали/по часовой стрелке до тех пор, пока все маркеры не будут закрыты.

  • Сначала сначала разрешайте что-либо в скобках!

Пример:

             +-------+
             | +-+   |
             | ^ |   |
        char *str[10];
         ^   ^   |   |
         |   +---+   |
         +-----------+

Question we ask ourselves: What is str?

``str is an...

- We move in a spiral clockwise direction starting with `str' and the first character we see is a `[' so, that means we have an array, so...
  ``str is an array 10 of...

- Continue in a spiral clockwise direction, and the next thing we encounter is the `*' so, that means we have pointers, so...
  ``str is an array 10 of pointers to...

- Continue in a spiral direction and we see the end of the line (the `;'), so keep going and we get to the type `char', so...
``str is an array 10 of pointers to char''

We have now ``visited'' every token; therefore we are done!

Ответ 7

из http://cdecl.org/

объявить foo как функцию, возвращающую указатель на массив SIZE массива SIZE указателя на функцию, возвращающую указатель на float