2010-07-15 29 views
0

J'ai quelques structures à initialiser, ce qui serait fastidieux à faire manuellement. Je voudrais créer une macro qui va m'aider avec ça ... mais je ne suis pas sûr que le préprocesseur C est assez bon pour ça.Initialisation de la structure par l'utilisation excessive de la macro

J'ai des structures qui représentent des menus. Ils consistent en des pointeurs de fonction seulement:

typedef uint8_t (*button_handler) (uint8_t); 
typedef void (*pedal_handler) (void); 
typedef void (*display_handler) (void); 
typedef void (*menu_switch_handler) (void); 

#define ON_BUTTON(x) uint8_t menu_frame_##x##_button (uint8_t button) 
#define ON_PEDAL(x) void menu_frame_##x##_pedal (void) 
#define ON_DISPLAY(x) void menu_frame_##x##_display (void) 
#define ON_SWITCH(x) void menu_frame_##x##_switch (void) 

typedef struct menu_frame { 
    button_handler on_button; 
    pedal_handler on_pedal; 
    display_handler on_display; 
    menu_switch_handler on_switch; 
} menu_frame; 

Cela me permet d'écrire les fonctions et les fonctions séparées que (fichier .c):

ON_BUTTON(blah) { ... } 

et menus comme (.h):

ON_BUTTON(blah); 
ON_DISPLAY(blah); 
menu_frame menu_frame_blah = { 
    menu_frame_blah_button, 
    NULL, 
    menu_frame_blah_display, 
    NULL 
}; 

Y at-il un moyen de plier la définition du menu en une définition? Je pouvais faire quelque chose qui se développe MENU(blah, menu_frame_blah_button, NULL, menu_frame_blah_display, NULL) bien sûr, mais est-il possible de:

  • rendent plus court (NULL ou un nom)
  • supprimer la nécessité de ON_BUTTON(...); d'avant la struct

Idéalement, j'aimerais que MENU(blah, button, NULL, display, NULL) définisse à la fois les gestionnaires et le menu struct lui-même. Je ne sais pas par exemple comment empêcher l'extension du dernier terme en ON_SWITCH(NULL).

Ou peut-être que je devrais l'aborder d'une autre manière?

+0

Essayez-vous d'écrire une version C de MFC? ;-) –

+0

Probablement :) En fait quelques trucs incorporés avec des charges de différents états de menu (assez qu'il serait stupide d'écrire beaucoup de lignes de ON_BUTTON (some_other_state)). – viraptor

Répondre

0

Vous ne pouvez pas effectuer d'expansion de macro conditionnelle en C, de sorte que votre macro serait étendue différemment en fonction des arguments, comme dans: vous ne pouvez pas utiliser #if dans la définition de macro.

Je suppose que le mieux que vous pourriez obtenir serait quelque chose comme MENU(blah, ITEM(blah,button), NULL, ITEM(blah,display), NULL), et vous avez toujours besoin d'un ensemble distinct pour les prototypes en raison du manque d'expansion conditionnelle. Personnellement, j'écrirais un script simple pour générer ce genre de code C standard. Celui qui comprendrait votre syntaxe désirée. En Python ou ce qui vous convient le mieux ...

+0

Je sais que je ne peux pas faire un conditionnel standard dans une macro, mais je comptais vraiment sur une syntaxe intéressante qui se réduit à un NOOP si elle est dépensée avec NULL, et à une déclaration si c'est quelque chose d'autre ... ne soit pas possible.Je vais essayer de générer à l'extérieur. – viraptor

+0

-1 parce que notre affirmation est fausse. Dans la bibliothèque du préprocesseur Boost, ils ont ce type de macros conditionnelles qui, selon un argument de macro, peuvent faire des choses différentes, par exemple BOOST_PP_EXPR_IF. –

+0

Alors, ferait-il un contrôle NULL? Parce que la source ici http://www.boost.org/doc/libs/1_41_0/boost/preprocessor/logical/bool.hpp suggère qu'il faut vraiment que la condition soit évaluée par le préprocesseur à un nombre compris entre 0 et 256. BOOST_PP_EXPR_IIF est une chose assez intelligente, cependant. –

1

J'ai écrit des scripts Python pour générer ce genre de code pour moi auparavant. Vous pouvez vouloir suivre cette route et juste travailler le script dans votre processus de construction.

0

Vous pouvez programmer des conditionnels, des boucles finies, des arguments par défaut et tous ces éléments dans le préprocesseur uniquement. La bibliothèque Boost en a implémenté une partie dans sa section préprocesseur. Boost est principalement pour C++, mais les choses du préprocesseur devraient aussi fonctionner en C.

Par de telles techniques, vous pouvez écrire des macros complexes mais simples à utiliser. Cela devient un peu plus simple à implémenter lorsque vous utilisez C99 au lieu de C89 (vous avez des initialiseurs nommés et VA_ARGS), mais quand même.

+0

Une raison particulière de refuser? (Actuellement +1 -2) –

+0

Je downvoted, parce que vous avez fait des revendications sans aucun exemple ou référence. Je ne sais pas si boost fait ce dont j'ai besoin avec le pré-traitement ou non, mais c'est un morceau de code trop grand pour le parcourir sans aucun pointeur spécifique. Si vous pouvez montrer un exemple qui pourrait résoudre ce problème, ce serait utile - sinon c'est comme dire "oui, c'est possible, mais vous devrez le trouver vous-même là-bas dans ce gros tas de code de la bibliothèque cryptique" - pas très utile. – viraptor

+2

@viraptor: Je n'ai pas donné d'exemples, car c'est vraiment compliqué (comme je l'ai dit) et ne correspondrait pas à une réponse appropriée ici. (Ok, je n'ai pas donné une référence à boost, mais je suppose que vous seriez en mesure de trouver cela.) Deuxièmement, la partie pré-processeur de boost n'est pas si cryptique, je trouve. Il a exactement les conditions que vous demandez dans la réponse que vous avez acceptée. Et puis juste downvoting sans donner une raison ou demander plus d'informations ... n'est pas très utile non plus. Simplement grossier, je dirais par quelqu'un qui a demandé de l'aide. –