2010-12-15 184 views
0

Je souhaite définir une macro au moment de la compilation en fonction de la valeur d'une autre macro. Toutefois, ce code n'est pas en cours d'exécution comme prévu:Problème de définition de macro étrange

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#define SIXTEEN 16 
#define TWO (SIXTEEN % 8 == 0)? (SIXTEEN/8) : ((SIXTEEN/8) + 1) 

int main(); 

int main() { 
    printf("max = %d\n", TWO); 
    int i; 
    for (i = 0; i < TWO; i++) { 
     printf("%d\n", i); 
    } 
    return 0; 
} 

Cette impression:

max = 2 
0 
1 
2 
... 

et se poursuit jusqu'à fin, quand il doit être simplement l'impression:

max = 2 
0 
1 

et en sortant.

Si je fais ça à la place, cela fonctionne:

#define TWO 2 

Je pensais que cela était un problème avec la définition de macro ... mais, si je fais ce qui suit avec le #define original, il semble travail:

... 
int count = TWO; 
for (i = 0; i < count; i++) { 
... 

Quelqu'un peut-il expliquer ce qui se passe ici?

Répondre

11

Le problème est que le TWO jeton est remplacé par les jetons avec lesquels vous avez défini la macro, donc ceci:

i < TWO 

devient ceci:

i < (SIXTEEN % 8 == 0)? (SIXTEEN/8) : ((SIXTEEN/8) + 1) 

En raison de la priorité des opérateurs, c'est lire comme:

(i < (SIXTEEN % 8 == 0)) 
    ? (SIXTEEN/8) 
    : ((SIXTEEN/8) + 1) 

Vous avez besoin de parenthèses supplémentaires pour TWO est remplacée par la liste de remplacement, vous obtenez le résultat souhaité:

#define TWO ((SIXTEEN % 8 == 0)? (SIXTEEN/8) : ((SIXTEEN/8) + 1)) 
      ^             ^

Lors de l'utilisation des macros, il est préférable d'utiliser des parenthèses où vous pouvez pour assurer le résultat est ce que vous attendez.

+0

+1 pour me battre de 37 secondes. = ( –

+2

+1 La règle générale est la suivante: si votre macro est supposée se développer dans une expression, assurez-vous qu'elle est incluse dans une paire de parens (correspondant), à la seule exception si elle est garantie de se développer en un seul jeton (comme la macro SIXTEEN de l'OP). –

1

Allongez la macro, et regardez votre boucle for après l'expansion macro:

for (i = 0; i < (16 % 8 == 0)? (16/8) : ((16/8) + 1); i++) 

Voir? i < (16 % 8 == 0) est l'état de l'opérateur ?:. Vous devez mettre une paire de parenthèses autour de la définition de TWO.

2

Entourez toujours les macros entre parenthèses car vous ne connaissez pas toujours le contexte dans lequel elles seront utilisées. Il peut arriver qu'un opérateur adjacent ait une priorité plus élevée et que la macro n'évalue pas correctement. L'utilisation de parenthèses n'est justifiée que si le symbole #define 'd est un seul jeton, tel que 5 ou "hello world". Si vous envisagez d'appeler votre macro avec des arguments qui sont des expressions et pas seulement des jetons simples, placez chaque occurrence de cet argument entre parenthèses pour la même raison que ci-dessus.

Une autre chose à éviter est de passer des expressions qui ont des effets secondaires en tant qu'arguments de macro.Si l'argument de macro correspondant est référencé plus d'une fois dans sa définition, l'évaluation sera effectuée plus d'une fois, et ce n'est généralement pas ce qui est souhaité.