72 votes

Déclaration complexe en C

Je parcourais simplement du code sur Internet et j'ai trouvé ceci :

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

Comment puis-je lire cette déclaration ? Y a-t-il un ensemble spécifique de règles pour lire de telles déclarations complexes ?

22 votes

16 votes

0 votes

Utiliser cdecl.org

122voto

Kos Points 29125

Je n'ai pas fait ça depuis un moment!

Commencez par foo et allez à droite.

float * (*(*<code>foo()</code>)[SIZE][SIZE])()

foo est une fonction sans arguments...

Impossible d'aller à droite car il y a une parenthèse fermante. Allons à gauche:

float * (*(<code>* foo()</code>)[SIZE][SIZE])()

foo est une fonction sans arguments retournant un pointeur

Impossible d'aller plus à gauche, alors traversons les parenthèses et allons à droite à nouveau

float * (*``[SIZE][SIZE])() float * (*``[SIZE])() float * (*``)()

foo est une fonction sans arguments retournant un pointeur vers un tableau de SIZE tableaux de SIZE ...

Parenthèse fermante atteinte, allons à gauche de nouveau pour atteindre un symbole de pointeur:

float * (<code>(( foo())[SIZE][SIZE]</code>)()

foo est une fonction sans arguments retournant un pointeur vers un tableau de SIZE tableaux de SIZE pointeurs vers ...

Encore une fois à gauche de la parenthèse, alors nous la traversons et allons à droite à nouveau:

float *``() float *

foo est une fonction sans arguments retournant un pointeur vers un tableau de SIZE tableaux de SIZE pointeurs vers une fonction sans arguments...

Et à gauche jusqu'à la fin

<code>float ( (* foo())[SIZE][SIZE])()</code>

foo est une fonction sans arguments retournant un pointeur vers un tableau de SIZE tableaux de SIZE pointeurs vers une fonction sans arguments retournant un pointeur vers float


Et à celui qui a écrit ça, s'il vous plaît apprenez-lui à utiliser typedef:

// Fonction qui retourne un pointeur vers un float
typedef float* PFloatFunc ();

// Tableau de pointeurs vers des fonctions PFloatFunc
typedef PFloatFunc* PFloatFuncArray2D[SIZE][SIZE];

// Fonction qui retourne un pointeur vers un PFloatFuncArray2D
PFloatFuncArray2D* foo();

59 votes

+1 pour "Et à celui qui a écrit cela, merci de lui apprendre à utiliser typedef"

3 votes

Veuillez noter que la partie "sans arguments" est uniquement correcte pour C ++; pour C, cela signifie "liste d'arguments non spécifiée" (mais cela ne peut pas être une fonction variadique car celles-ci doivent avoir un prototype complet en portée, même en C).

101voto

John Bode Points 33046

Règle standard : Trouvez l'identificateur le plus à gauche et travaillez votre chemin à partir de là, en vous rappelant que [] et () lient avant * :

            foo                      -- foo
            foo()                    -- est une fonction
           *foo()                    -- renvoyant un pointeur
          (*foo())[SIZE]             -- vers un tableau de taille SIZE
          (*foo())[SIZE][SIZE]       -- de tableaux de taille SIZE
         *(*foo())[SIZE][SIZE]       -- de pointeurs
        (*(*foo())[SIZE][SIZE])()    -- vers des fonctions
      * (*(*foo())[SIZE][SIZE])()    -- renvoyant des pointeurs
float * (*(*foo())[SIZE][SIZE])();   -- vers du float

Imaginez maintenant que vous avez une série de fonctions renvoyant des pointeurs vers float :

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

Disons que vous voulez les stocker dans un tableau 2x2 :

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

tab est un tableau de taille SIZE x SIZE de pointeurs vers des fonctions renvoyant des pointeurs vers float.

Maintenant, décidons que nous voulons une fonction qui renvoie un pointeur vers ce tableau :

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

Notez que vous pourriez avoir plusieurs fonctions qui construisent des tableaux de fonctions différentes, ou organiser les mêmes fonctions différemment :

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

C'est la seule raison à laquelle je pense pour faire quelque chose comme cela. Vous ne devriez pas voir des types comme celui-ci couramment (bien qu'ils apparaissent de temps en temps, et j'ai été coupable d'écrire quelque chose de similaire).

1 votes

Qwerbl? Vous avez presque épuisé les noms de variables génériques, n'est-ce pas :-) +1 pour la logique. Et je suis sûr que les types "profondément liés" apparaissent assez souvent, mais impliquent généralement des structures ou des classes également, ce qui résout naturellement le problème de nommage - comme ce serait le cas ici en introduisant quelques typedefs.

0 votes

@Kos : ouais. Je n'ai pas encore eu ma dose quotidienne de caféine, je n'ai pas pu trouver mieux.

1 votes

Wikipedia a une liste de variables métasyntaxiques afin que vous ne manquiez pas : foo, bar, baz, qux, quux, corge, grault, garply, waldo, fred, plugh, xyzzy, thud.

6voto

Clement J. Points 2579

Selon cdecl.org

declare foo as function returning pointer to array SIZE of array SIZE of pointer to function returning pointer to float

Utilisez la règle du spirale donnée par Luchian Grigore si vous voulez le décoder à la main.

4voto

QuentinUK Points 995

La meilleure chose à faire ici est de convertir en une série de typedefs.

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

2 votes

Il m'a fallu plus d'une minute pour faire ça.

3voto

Component 10 Points 4512

En général, vous pourriez essayer cdecl.org mais vous auriez besoin de remplacer par SIZE

Disons que vous remplacez SIZE par 12, vous obtiendriez:

déclarez foo comme une fonction renvoyant un pointeur vers un tableau 12 de tableau 12 de pointeur vers une fonction renvoyant un pointeur vers un flottant

Je ne suis pas sûr que cela vous aide vraiment !

Deux observations ici :

  1. Je suppose que ce code n'avait pas de commentaire à côté expliquant quel était son but (c'est-à-dire non pas l'explication technique de ce qu'il est mais ce qu'il réalise d'un point de vue fonctionnel / métier). Si un programmeur a besoin d'utiliser quelque chose d'aussi complexe que cela, il devrait être assez bon pour expliquer aux futurs mainteneurs quel est son but.
  2. Certainement en C++, il y a des moyens plus évidents et probablement plus sûrs d'atteindre le même résultat.

3 votes

Ceci est dû à la "SIZE", vous devez utiliser une littérale à la place (et la remplacer vous-même par la constante après).

0 votes

Remplacez TAILLE par un nombre quelconque !!

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X