2009-10-13 5 views
18

Comme les questions l'indiquent, le préprocesseur C peut-il le faire?Le préprocesseur C peut-il effectuer un calcul arithmétique?

.: par exemple

#define PI 3.1416 
#define OP PI/100 
#define OP2 PI%100 

Y at-il OP moyen et/ou OP2 se calcule dans la phase de pré-traitement?

+4

PI est pas un nombre entier dans l'exemple; par conséquent, ni OP ni OP2 ne seraient des entiers si le préprocesseur était forcé de les évaluer. Et les opérandes de '%' ne peuvent pas être des nombres à virgule flottante. –

Répondre

25

Arithmétique entière? Exécutez le programme suivant pour savoir:

#include "stdio.h" 
int main() { 
    #if 1 + 1 == 2 
     printf("1+1==2\n"); 
    #endif 
    #if 1 + 1 == 3 
     printf("1+1==3\n"); 
    #endif 
} 

réponse est « oui », il y a un moyen de faire le préprocesseur effectuer l'arithmétique entière, ce qui est de l'utiliser dans un état de préprocesseur.

Notez cependant que vos exemples ne sont pas arithmétiques entiers. Je viens de vérifier, et le préprocesseur de gcc échoue si vous essayez de le faire faire des comparaisons flottantes. Je n'ai pas vérifié si la norme autorise l'arithmétique à virgule flottante dans le préprocesseur.

macro expansion régulière n'évalue pas les expressions entières, il laisse au compilateur, comme on peut le voir par prétraiter (-e gcc) les éléments suivants:

#define ONEPLUSONE (1 + 1) 
#if ONEPLUSONE == 2 
    int i = ONEPLUSONE; 
#endif 

Le résultat est int i = (1 + 1); (plus probablement des choses pour indiquer les noms de fichier source et les numéros de ligne et autres).

+6

Chris: Nous vivons dans le futur maintenant, et alors que les voitures volantes sont toujours manquantes, les valeurs de retour par défaut de la fonction principale sont arrivées! –

+11

@Chris: une accolade fermée, qui atteint "renvoie une valeur de 0" (5.1.2.2.3, terminaison de programme). Si je ne suis pas autorisé à assumer le standard C dans une question marquée "C", alors à quoi sert le monde? Est-ce que vous ne trouvez pas quelqu'un qui utilise des commentaires de style // dans du code qui pourrait être vu par un compilateur C89, et qui se plaint à leur place? ;-) –

+0

@Chris - L'accolade de fermeture? :-) –

13

Le code que vous avez écrit ne fait en réalité aucun calcul au préprocesseur. Un #define fait simple remplacement de texte, donc avec cette définition:

#define PI 3.1416 
#define OP PI/100 

Ce code:

if (OP == x) { ... } 

devient

if (3.1416/100 == x) { ... } 

puis il se compile. Le compilateur à son tour peut choisir de prendre une telle expression et calculer au moment de la compilation et produire un code équivalent à ceci:

if (0.031416 == x) { ... } 

Mais c'est le compilateur, pas le préprocesseur.

Pour répondre à votre question, oui, le préprocesseur peut faire un peu d'arithmétique. Cela peut être vu lorsque vous écrivez quelque chose comme ceci:

#if (3.141/100 == 20) 
    printf("yo"); 
#elif (3+3 == 6) 
    printf("hey"); 
#endif 
+3

Malheureusement, si vous essayez votre extrait de compilation conditionnel, vous obtenez le message de GCC:' x.c: 5: 6: erreur: constante flottante dans l'expression du préprocesseur'. Vous pouvez faire de l'arithmétique entière avec le pré-processeur C; vous ne pouvez pas faire d'arithmétique en virgule flottante avec. –

+0

ressemble à des coins coupés par gcc ici, Stroustrup C++ 2ème édition r.16.5 '#if expression-constante',' r.5.19 expression constante': ​​"... les constantes flottantes doivent être moulées en types entiers". – denis

6

OUI, je veux dire: il peut faire de l'arithmétique :)

Comme le montre 99 bottles of beer.

+0

Un bel exemple! :) – Avio

4

Oui.

Je ne peux pas croire que personne n'a encore lié à un certain gagnant du concours C obfusqué. Le gars a implémenté une ALU dans le préprocesseur via des inclusions récursives. Here est la mise en œuvre, et here est quelque chose d'une explication. Maintenant, cela dit, vous ne voulez pas faire ce que ce mec a fait.C'est amusant et tout, mais regardez les temps de compilation dans son fichier de conseil (pour ne pas mentionner le fait que le code résultant est impossible à maintenir). Plus communément, les gens utilisent strictement le pré-processeur pour le remplacement du texte, et l'évaluation de l'arithmétique des nombres constants se produit soit au moment de la compilation, soit au moment de l'exécution.

Comme d'autres l'ont noté cependant, vous pouvez faire un peu d'arithmétique dans les instructions #if.

+1

http://stackoverflow.com/questions/652788/quand-est-le-worst-real-world-macros-pre-processor-abuse-youve-ever-come-across/1242177#1242177 - chaos-pp . Abus de préprocesseur avec style. –

6

Oui, cela peut être fait avec le préprocesseur Boost. Et il est compatible avec le C pur donc vous pouvez l'utiliser dans les programmes C avec des compilations C seulement. Votre code implique des nombres à virgule flottante, donc je pense que cela doit être fait indirectement.

#include <boost/preprocessor/arithmetic/div.hpp> 
BOOST_PP_DIV(11, 5) // expands to 2 
#define KB 1024 
#define HKB BOOST_PP_DIV(A,2) 
#define REM(A,B) BOOST_PP_SUB(A, BOOST_PP_MUL(B, BOOST_PP_DIV(A,B))) 
#define RKB REM(KB,2) 

int div = HKB; 
int rem = RKB; 

Cette prétraite à (vérifier avec -S gcc)

int div = 512; 
int rem = 0; 

Merci à this thread.

Questions connexes