Le mélange des variables et des constantes entières dans le préprocesseur Boost

StackOverflow https://stackoverflow.com/questions/3884489

  •  28-09-2019
  •  | 
  •  

Question

J'utilise BOOST_PP pour faire des calculs précompiler dans le préprocesseur. Je me concentre sur une application où la taille du code est très important pour moi. (Donc, s'il vous plaît ne dites pas le compilateur devrait ou habituellement est-ce que, je dois contrôler ce qui est effectué au moment de la compilation et ce code est généré). Cependant, je veux être en mesure d'utiliser le même nom de la fonction macro / pour les constantes entières et des variables. Comme exemple trivial, je peux avoir

#define TWICE(n) BOOST_PP_MUL(n,2)
//.....
// somewhere else in code
int a = TWICE(5);

fait ce que je veux qu'il, évaluer à

int a = 10;

pendant la compilation.

Mais je veux aussi qu'il soit utilisé à

int b = 5;
int a = TWICE(b);

Cela devrait être prétraité à

int b = 5;
int a = 5 * 2;

Bien sûr, je peux le faire en utilisant les macros traditionnelles comme

#define TWICE(n) n * 2

Mais il ne marche pas faire ce que je veux faire pour les constantes entières (les évaluer lors de la compilation).

Alors, ma question est, est-il une astuce pour vérifier si l'argument est un littéral ou une variable, puis utiliser des définitions différentes. à-dire quelque chose comme ceci:

#define TWICE(n) BOOST_PP_IF( _IS_CONSTANT(n), \
                              BOOST_PP_MUL(n,2), \
                              n * 2 )

modifier: Donc ce que je suis vraiment après un moyen de vérifier si quelque chose est une constante disponible au moment de la compilation, et donc un bon argument pour les fonctions de BOOST_PP_. Je me rends compte que ceci est différent de ce que la plupart des gens attendent d'une des recommandations de programmation préprocesseur et générales. Mais il n'y a pas mauvais de la programmation façon, donc s'il vous plaît ne déteste pas sur la question si vous n'êtes pas d'accord avec sa philosophie. Il y a une raison pour laquelle la bibliothèque existe BOOST_PP, et cette question est dans le même esprit. Il pourrait tout simplement pas possible cependant.

Était-ce utile?

La solution

Vous essayez de faire quelque chose qui est préférable de laisser aux optimisations du compilateur.

int main (void) {
  int b = 5;
  int a = b * 2;

  return a; // return it so we use a and it's not optimized away
}

-s gcc -O3 t.c

 .file "t.c"
 .text
 .p2align 4,,15
.globl main
 .type main, @function
main:
.LFB0:
 .cfi_startproc
 movl $10, %eax
 ret
 .cfi_endproc
.LFE0:
 .size main, .-main
 .ident "GCC: (Debian 4.5.0-6) 4.5.1 20100617 (prerelease)"
 .section .note.GNU-stack,"",@progbits

L'optimisation de compilateur optimiser.

EDIT: Je suis conscient que vous ne voulez pas entendre que le compilateur « devrait » ou « habituellement » le fait. Cependant, ce que vous essayez de faire est pas quelque chose qui est censé être fait dans le préprocesseur C; les personnes qui ont conçu le langage C et C préprocesseur conçus pour fonctionner avec le pré-traitement jeton atome de base est tout. Le RPC est, à bien des égards, « stupide ». Ce n'est pas une mauvaise chose (en fait, cela est dans de nombreux cas, ce qui le rend si utile), mais à la fin de la journée, il est un préprocesseur. Il prétraite les fichiers source avant qu'ils ne soient analysés. Il prétraite les fichiers source avant l'analyse sémantique se produit. Il prétraite les fichiers source avant la validité d'un fichier source donnée est cochée. Je comprends que vous ne voulez pas entendre que c'est quelque chose que l'analyseur et l'analyseur sémantique doit manipuler ou le fait habituellement. Cependant, ceci est la réalité de la situation. Si vous souhaitez concevoir un code qui est incroyablement petit, alors vous devriez compter sur votre compilateur pour faire son travail au lieu d'essayer de créer des constructions de préprocesseur pour faire le travail. Pensez-y de cette façon: des milliers d'heures de travail ont été dans votre compilateur, essayez donc de réutiliser autant que possible que le travail

Autres conseils

pas tout à fait l'approche directe, cependant:

struct operation {
    template<int N>
    struct compile {
        static const int value = N;
    };
    static int runtime(int N) { return N; }
};

operation::compile<5>::value;
operation::runtime(5);

alternativement

operation<5>();
operation(5);

Il n'y a aucune chance de mélanger les deux niveaux (préprocesseur et évaluation de Variables ). D'après ce que je comprends de votre question, b devrait être une constante symbolique?

Je pense que vous devriez utiliser le traditionnel

#define TWICE(n) ((n) * 2)

mais au lieu d'initialiser les variables avec des expressions, vous devez les initialiser avec des constantes de temps de compilation. La seule chose que je vois pour forcer l'évaluation au moment de la compilation et d'avoir des constantes symboliques en C sont des constantes d'énumération intégrales. Ceux-ci sont définis pour avoir le type int et sont évalués au moment de la compilation.

enum { bInit = 5 };
int b = bInit;
enum { aInit = TWICE(bInit) };
int a = aInit; 

Et vous ne devriez pas être trop généralement Thrifty avec const (comme pour votre b) et vérifier l'assembleur produit avec -S.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top