C fournit un moyen pour placer le code syntaxiquement avant tout autre code qui sera exécuté en premier: l' for
bloc. Rappelez-vous que la clause 3 for
structure peut contenir une expression arbitraire, et court toujours après l'exécution du bloc principal.
Vous pouvez donc créer une macro qui fait un prédéterminés d'appel après un bloc d' suivants du code en l'enveloppant d'un for
bloc dans une macro:
#define M_GEN_DONE_FLAG() _done_ ## __LINE__
#define M_AROUND_BLOCK2(FLAG, DECL, BEFORE, AFTER) \
for (int FLAG = (BEFORE, 0); !FLAG; ) \
for (DECL; !FLAG; FLAG = (AFTER, 1))
#define M_AROUND_BLOCK(DECL, BEFORE, AFTER) M_AROUND_BLOCK2(M_GEN_DONE_FLAG(), DECL, BEFORE, AFTER)
#define M_CLEANUP_VAR(DECL, CLEANUP_CALL) M_AROUND_BLOCK(DECL, (void)0, CLEANUP_CALL)
...et vous pouvez l'utiliser comme ceci:
#include <stdio.h>
struct proc;
typedef struct proc * proc_t;
proc_t proc_find(int);
void proc_rele(proc_t);
void fun(int mypid) {
M_CLEANUP_VAR (proc_t myproc = proc_find(mypid), proc_rele(myproc))
{
printf("%p\n", &myproc); // just to prove it's in scope
}
}
Le truc c'est qu'un for
bloc accepte une déclaration suivante, mais si nous ne sommes pas en mettre qu'énoncé dans la définition de la macro, on peut suivre la macro invocation avec un bloc de code et il sera "comme par magie" appartiennent à notre nouveau l'étendue de contrôle de la structure de la syntaxe, tout simplement parce qu'à la suite de la élargi for
.
Toute l'optimiseur de dollars à l'aide permettra de supprimer la boucle de drapeau à son niveau le plus bas des paramètres d'optimisation. Notez que le nom des affrontements avec le drapeau n'est pas une préoccupation énorme (c'est à dire que vous n'avez pas vraiment besoin d'un gensym
- ce parce que le drapeau est l'étendue du corps de la boucle, et toutes les boucles imbriquées en toute sécurité les masquer, si ils utilisent le même nom d'option.
La prime ici, c'est que la portée de la variable de nettoyage est limité (il ne peut pas être utilisé en dehors de l'enceinte immédiatement après sa déclaration) et visuellement explicite (à cause du dit composé).
Pour:
- c'est la norme C sans extensions
- le flux de contrôle est simple
- c'est en fait (en quelque sorte) moins verbeux que
__attribute__ __cleanup__
Inconvénients:
- il ne fournit pas "plein" RAII (c'est à dire de ne pas protéger contre
goto
ou les exceptions C++: __cleanup__
est généralement mis en œuvre avec le C++ machines sous le capot, donc il est plus complet). Plus sérieusement, elle ne protège pas contre les premiers return
(merci @Voo). (Vous pouvez au moins se prémunir contre un éventuel break
- si vous voulez - par l'ajout d'une troisième ligne, switch (0) default:
à la fin de l' M_AROUND_BLOCK2
.)
- pas tout le monde est d'accord avec la syntaxe de l'extension de macros (mais considérez que vous êtes l'extension de C de la sémantique, donc...)