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

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

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

Как я могу прочитать эту декларацию? Есть определенный набор правил для чтения таких сложных деклараций?

7 ответов


я давно этого не делал!

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

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

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

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

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

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

не может идти влево дальше, так что давайте пересечем скобки и снова направо

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

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

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

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

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

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

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

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

и до конца

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

foo-это функция без аргументов, возвращающая указатель на массив размера массивы указателей размера функции без аргументов, возвращающих указатель на 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();

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

            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 представляет собой размер X размер массива указателей на функции, возвращающие указатели на 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;
}

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


согласно cdecl.org

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

используйте спиральное правило, данное Лучианом Григоре, если вы хотите расшифровать его вручную.


лучше всего здесь преобразовать в серию typedefs.

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

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

скажите, что вы меняетесь SIZE для 12, вы получите:

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

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

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

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

этот документ дает мне лучший ключ о том, как легко подготовить любую декларацию C:

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

есть три простых шага, чтобы следовать:

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

    • [X] или [] = > массив X размер ... или массив неопределенного размера ...

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

    • * => указатель(ы) на ...

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

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

пример :

             +-------+
             | +-+   |
             | ^ |   |
        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!

от http://cdecl.org/

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