7
votes

Fonctions de préprocesseur évaluées au moment de la compilation en C

Je veux écrire des fonctions / des tableaux de préprocesseur qui sont évalués à Compiler le temps. Par exemple, si je définis xxx

puis, le code xxx

doit être présenté comme xxx

au compilateur. (Bien sûr, seuls les littéraux peuvent être utilisés dans l'indice). Ceci est important si la taille / la mémoire du code est critique et que nous ne voulons pas Store Myarr , mais nous en avons besoin de la commodité de codage.

Les fonctions de compilation de la compilation seraient également bonnes. Par exemple, quelque chose comme xxx

donc, la déclaration xxx

doit être présentée au compilateur comme XXX

Évidemment, nous devons utiliser un littéral comme argument. Est-ce possible?


1 commentaires

+1 Parce que cela s'avère une question beaucoup plus intéressante qu'il ne semblait au premier abord.


5 Réponses :


0
votes

myarr pour les caractères que je peux faire xxx

toujours réfléchir à des intenses. MyMap est xxx


3 commentaires

Votre myarr serait mieux à faire (((((((chartons *) "1234567") [x])


@Jens: le const ne fait aucune différence. Modifier les littéraux de chaîne est un comportement indéfini afin que le compilateur soit libre de les mettre en stockage constant partagé de toute façon, et dans la pratique, cela le fera.


@R.: Cela fait une différence pour l'appelant. Vous ne pouvez pas accidentellement prendre le résultat comme un lvalue et la modifier. myMap (2) = 27; serait autorisé (bien que UB) dans la version d'origine, mais produisez une erreur de compilation avec le const . Je pense que pour les macros comme ça, vous devez être le plus prudent, puisqu'un utilisateur potentiel ne maîtrise de force toutes les conséquences.



2
votes

Le préprocesseur C standard C ne fera pas ce que vous voulez. Pour obtenir ce type de comportement de manière fiable, vous aurez besoin d'un outil de prétraitement non puissant et non puissant. Cependant, je ne suis pas assez familier avec ce qui est disponible pour vous diriger vers lequel vous voudrez peut-être.

Bien que, dans le second cas, vous pourrez toujours avoir l'effet que vous souhaitez sur la plupart des compilateurs modernes. Par exemple: xxx

sera toujours présenté au compilateur comme: xxx

mais Le compilateur lui-même, s'il s'agit d'un compilateur moderne raisonnable et que vous lui permettriez d'optimiser, vous remarquerez probablement que cette expression peut être évaluée à la compilée et émettre du code identique à xxx

Cependant, il n'y a rien que garantit qu'un compilateur effectuera cette optimisation.


1 commentaires

Vous pouvez faire des méta-programmations de préprocesseur comme Boost.PP prouve. Son unique encombrant et bien sûr limitée concernant les types de données que vous pouvez travailler.



0
votes

Il n'y a pas de commandes de préprocesseur standard qui gèrent des tableaux comme vous manquez. Je suggère que vous utilisiez un const. xxx

puis pour la question MyMap ... xxx


0 commentaires

5
votes

Sûr c'est possible. Bien que vous puissiez le faire manuellement, Boost.preprocessor A > Vous donne déjà les outils dont vous avez besoin:

#define MYMAP(x) BOOST_PP_IF(BOOST_PP_EQUAL(x, 1), 5, 2)
pour extraire les composants du pré-dépresseur. P>


10 commentaires

@Georg: Dans moderne C AKA C99, vous pouvez programmer beaucoup plus simple (et plus facile à lire) que de booster le fait. Boost est limité par le manque de macros variadiques en C ++. Mais avec des littéraux composés, vous l'obtenez même directement, pas besoin d'acrobaties ;-)


@Jens: Bon point - En tant qu'utilisateur principalement C ++, je n'ai pas encore examiné les modèles d'utilisation avec des macros variadiques.


@R ..: Euh, pourquoi? Boost.PP fonctionne de la même manière - préféreriez-vous réexamener toutes les structures de contrôle vous-même?


BOOST.PP n'est pas C. Je donnerais également A -1 pour une recommandation d'écrire un script Perl pour générer un code C, tant que la question était à propos de C et du préprocesseur C.


@R ..: Boost.PP fonctionne avec les préprocesseurs communs que je connais et ne dépend de aucun comportement C ++. Ce qui précède fonctionne avec C et son préprocesseur, donc je ne vois donc pas comment une comparaison avec un script perl convient.


@Georg, wow. Et moi, cependant, le métaprogrammation de modèle était effrayant et que le prétraiteur C n'était pas capable de m'écarter si mal. N'était-ce pas tort. Maintenant, je suis obligé d'en savoir plus sur Boost.PP ...


@RBERTEG, @georg: Pour ceux qui aiment C99 :) J'ai programmé une bibliothèque (les fichiers incluent bien) P99 entièrement basé sur des fonctionnalités de C99. Il n'est pas encore publié mais vous avez peut-être déjà un coup d'œil dans la documentation que j'ai mis en ligne: P99 .gforge.inria.fr / p99-html


@Jens: Nice, semble prometteur. Vous envisagez d'ajouter Enum , Enum_params , et al? :)


@Georg: toute sorte de "code déroulant" que vous voulez. Voir par exemple p99.gforge.inria.fr/p99-html/group__statement__lists.html < / a> (Si vous souhaitez discuter de cela, prenons ensuite cette discussion à d'autres canaux.)


Cela s'est avéré être la meilleure solution et oui, il est compatible avec Pure C. Merci! J'ai une question de suivi sur la tentative de sélectionner s'il faut faire un calcul du préprocesseur par rapport au calcul du temps d'exécution. Je suppose que je soutiendrai une nouvelle question.



2
votes

en C99 (vous avez vraiment besoin de cela, C89 ne ferait pas) que vous pouvez faire quelque chose comme xxx

à condition que votre type soit int , mais tout autre type ferait. La chose étrange (int const []) {3, 4, 5, 6, 7} est appelée littéral composé. Le const là-bas pour le type de base indique au compilateur qu'il ne sera pas modifié et qu'il peut alias tous ces événements avec le même contenu sur le même emplacement fixe.

Modifier, après la remarque de CAF: Généralement, pour cette approche, la plupart des compilateurs pourront optimiser complètement toute référence à la matrice, à condition que n est une expression qui peut être évaluée à la compilation, telle qu'une valeur fixe 7 < / code> ou 'a' ou ainsi.

Si ce n'est pas le cas, le compilateur doit créer un objet de réseau quelque part. Avec le const , il pourrait être autorisé à générer une seule copie de celui-ci, quelle que soit la fréquence à laquelle vous appelez la macro dans votre code. Lorsqu'il réussit à le faire, l'initialisation de la matrice serait effectuée à l'heure de la compilation. Il n'y aurait donc aucun moment de compilation.

J'ai vérifié ceci pour les trois compilateurs que j'ai sur ma machine: < / p>

  • gcc et clang allouer le tableau sur la pile et ceci pour chaque single Appelez à MyMap , Bad , puisque la surcharge est proportionnelle à la taille de la matrice.
  • opencc alloue le tableau statique mais crée une nouvelle copie pour chaque appel à myMap , meilleur mais pas encore idéal.

2 commentaires

Si vous souhaitez autoriser l'optimisation du tableau lui-même, vous devez faire attention à ne pas transmettre une variable à la macro.


@CAF: Oui, l'OP a parlé de littéraux . Mon hypothèse était qu'il voulait dire compiler des expressions constantes de temps. J'ajoute ça à ma réponse.