Les fonctions anonymes à l'aide de GCC déclaration des expressions
Cette question n'est pas très précis; c'est vraiment pour mon propre C d'enrichissement et j'espère que d'autres peuvent le trouver utile.
Avertissement: je sais que beaucoup vont avoir l'impulsion de répondre avec des "si vous essayez de faire les FP alors il suffit d'utiliser un langage fonctionnel". Je travaille dans un environnement intégré qui a besoin d'accéder à de nombreux autres bibliothèques C, et n'a pas beaucoup de place pour beaucoup plus de grands shared libs et ne prend pas en charge la langue de nombreux environnements d'exécution. En outre, l'allocation de mémoire dynamique est hors de question. Je suis aussi vraiment curieux.
Beaucoup d'entre nous ont vu cette chouette C macro pour les expressions lambda:
#define lambda(return_type, function_body) \
({ \
return_type __fn__ function_body \
__fn__; \
})
Et un exemple d'utilisation est:
int (*max)(int, int) = lambda (int, (int x, int y) { return x > y ? x : y; });
max(4, 5); //Example
À l'aide de gcc -std=c89 -E test.c
, le lambda s'étend à:
int (*max)(int, int) = ({ int __fn__ (int x, int y) { return x > y ? x : y; } __fn__; });
Donc, voici mes questions:
-
Que signifie exactement la ligne int (*X); déclarer? Bien sûr, int * X; est un pointeur vers un entier, mais comment ces deux diffèrent-ils?
-
De prendre un coup d'oeil à la exapnded macro, ce qui sur terre ne le final
__fn__
faire? Si j'écris une fonction de testvoid test() { printf("hello"); } test;
- qui jette tout de suite un message d'erreur. Je ne comprends pas cette syntaxe. -
Qu'est-ce que cela signifie pour le débogage? (J'ai l'intention de me expérimenter avec cela et gdb, mais d'autres expériences ou opinions serait génial). Serait-ce que vis analyseurs statiques?
- Aussi, je ne vois pas
int (*X);
n'importe où. - Ce n'est pas là en tant que tel. Tout en essayant de comprendre la syntaxe, j'ai été un peu perplexe que int (*X); compile, mais pas vraiment sûr de ce qu'il a défini..
int (*X)(<arguments>);
est un prototype pour un pointeur de fonction par le nom deX
. En d'autres termes:X
est un pointeur vers une fonction acceptant<arguments>
et retour d'unint
.- Alors, disons que nous avons juste
int (*x)
- c'est un pointeur vers une fonction... une liste variable d'arguments, pas d'arguments? - Et comment est-ce pas le C ANSI? Par convention? parce qu'il compile sous -std=c89
- Pour faire gcc strict C89 (ou C99) compilateur, utilisez
-std=c89 -pedantic
. - Parce que le mécanisme ici (déclaration expressions) ne sont pas dans la norme(s).
- Vous avez besoin de la
()
s parce que sinon vous vous retrouvez en avant-déclarantX
comme une fonction retournant un pointeur versint
. - Aussi, les fonctions imbriquées entrent en jeu, qui sont un GCC extension.
- Alors, comment faisons-nous des fonctions anonymes en C ANSI?
- nous n'avons pas. Simplement pas pris en charge.
int (*x)
est équivalent àint *x
, c'est à dire un pointeur (*
) int.int *x()
est une fonction retournant un pointeur sur int. Avis le problème ici: le paramètre-liste de demande de déclaration (()
) a une plus grande priorité de l'opérateur que le pointeur (*
). Pour remplacer cela, utilisez les parenthèses:int (*x)()
est un pointeur (*
) à une fonction (()
) de prendre quelconque d'arguments, de retour de type int. cdecl.org
Vous devez vous connecter pour publier un commentaire.
Cette déclaration (au bloc de portée):
n'est pas C, mais est valable GNU C.
Il fait usage de deux
gcc
extensions:Les deux fonctions imbriquées (la définition d'une fonction à l'intérieur d'une instruction composée) et déclaration des expressions (
({})
, essentiellement un bloc qui donne une valeur) ne sont pas autorisés dans C et viennent de GNU C.Dans une déclaration à l'expression, la dernière expression est la valeur de la construction. C'est pourquoi la fonction imbriquée
__fn__
apparaît comme l'expression d'une déclaration à la fin de l'énoncé de l'expression. Une fonction de désignation (__fn__
dans la dernière expression de l'énoncé) dans une expression, est converti en un pointeur vers une fonction par l'habitude de conversions. C'est la valeur utilisée pour initialiser le pointeur de fonctionmax
.Votre lambda macro exploite deux funky fonctionnalités. La première utilise les fonctions imbriquées à fait définir le corps de votre fonction (donc vos lambda n'est pas vraiment anonyme, il utilise juste un implicite
__fn__
variable (qui devrait être renommé à autre chose, comme la double-pointe-de souligner les noms sont réservés pour le compilateur, donc peut-être quelque chose commeyourapp__fn__
serait mieux).Tous c'est elle-même réalisée dans un GCC composé de déclaration (voir http://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html#Statement-Exprs), le format de base de ce qui va quelque chose comme:
la dernière déclaration de l'instruction composée adresse de la fonction déclarée. Maintenant,
int (*max)(int,int)
obtient tout simplement la valeur de l'instruction composée, qui est maintenant le pointeur de la "anonyme" de la fonction juste déclaré.De débogage macros sont une douleur royale de cours.
Que la raison pourquoi
test;
.. au moins, ici, je reçois le test redéclarée que les différents type de symbole", ce qui je suppose signifie GCC est de le traiter comme une déclaration et non une (inutile) de l'expression. Parce que les variables non typées par défaut pourint
et parce que vous avez déjà déclarétest
comme une fonction (essentiellement,void (*)(void)
), vous obtenez.. mais je peux me tromper à ce sujet.Ce n'est pas portable par un effort d'imagination si.
__fn__
.Réponse partielle:
Il n'est pas int(*X) qui vous intéresse. Il est de type int (*X)(y,z). C'est un pointeur de fonction à la fonction appelée X qui prend (y,z) et retourne int.
Pour le débogage, ce sera vraiment dur. La plupart des débogueurs peuvent pas trace grâce à une macro. Vous serait le plus susceptible d'avoir pour déboguer l'assemblée.
int (*max)(int, int)
est le type de variable que vous déclarez. Il est défini comme un pointeur de fonction du nom de max qui retourne int, et prend deux entiers en paramètres.__fn__
désigne le nom de la fonction, qui dans ce cas est de max.Je n'ai pas de réponse. J'imagine que vous pouvez, si vous avez le lancer par le préprocesseur.
int (*max)(int, int) = ({ int __fn__ (int x, int y) { return x > y ? x : y; } __fn__; });
compiler, maisvoid test() { puts("hello"); } test;
pas compiler?void (*test)() = ({ void test() {puts("hello");} test; });
ou si cela ne fonctionne pas,void (*test)() = ({ void __fn__() { puts("hello");} __fn__; });
__fn__
est juste un nom arbitraire pour la fonction définie à l'intérieur du bloc. Le nom est malheureusement source de confusion.