1
votes

Sélection de macro de préprocesseur C ++ par argument

J'essaie de définir une macro de préprocesseur qui sélectionne à son tour la bonne macro en fonction de la valeur d'un argument.

#define BIT_8(n) n, "is lower or equal than 8"
#define BIT_N(n) n, "is greater than 8"
#define BIT(n) ?????

int main() {
    printf("%d %s", BIT(9));
    return 0;
}

BIT (n) devrait développer en:

BIT_8 (n) si n≤8
BIT_N (n) if n> 8

Comment y parvenir?


2 commentaires

Vous êtes sûr de ne pas vouloir à la place de if constexpr ?


Les macros de préprocesseur effectuent une substitution de texte assez simple. Le préprocesseur est un mauvais choix en tant que langage de programmation.


3 Réponses :


3
votes

À moins que vous ne vouliez du code très maladroit, vous ne pouvez pas faire cela. Le préprocesseur n'a aucune idée de la valeur de l'argument passé. Il ne fait que remplacer les chaînes et c'est tout.

Cela étant dit, ce sont des fous qui implémentent BIT_x pour tous les x de [0 à 63]. Ceci est très moche et échouerait est utilisé avec un argument défini à 64.

Une solution propre consiste à utiliser une fonction à la place:

const char * bit_msg(unsigned int b)
{
    if (b > 8) return "is greater than 8";
    const char * bits[] = {
"is 0 and lower than 8",
"is 1 and lower than 8",
"is 2 and lower than 8",
"is 3 and lower than 8",
"is 4 and lower than 8",
"is 5 and lower than 8",
"is 6 and lower than 8",
"is 7 and lower than 8",
"is 8",
}; 
return bits[b];
}

#define BIT(X) X, bit_msg(X)
[...]
printf("%d %s", BIT(9));

Parce que vous J'ai étiqueté la question avec C ++ et pour suivre @Romen, vous pourriez obtenir un résultat similaire en utilisant constexpr qui, si possible, sera calculé par le compilateur au moment de la compilation, ce qui donnera un code aussi efficace qu'une macro .

Dans l'exemple ci-dessus, il vous suffira de remplacer la signature par constexpr const char * bit_msg (unsigned int b) et le compilateur pourra même sauter la fonction et écrire (l'équivalent de) printf ("% d% s", 9, "est supérieur à 8") .


3 commentaires

Je voudrais ajouter à cette réponse en soulignant que le constexpr peut être utilisé pour réécrire les macros en tant que fonctions qui peuvent être évaluées au moment de la compilation. Idéalement, le code C ++ moderne ne devrait plus utiliser autant le préprocesseur.


Notez que l'implémentation de BIT_x pour tout x peut être faite pour fonctionner si vous appelez BIT (9) en utilisant le collage de jetons, cela échouera pour BIT (8 + 1)


@MartinBonner Vous avez parfaitement raison. Le préprocesseur est juste un "copier-coller", ce n'est pas un langage.



0
votes

vous pouvez faire ceci

#include <stdio.h>

#define BIT_8(n) printf("%d is lower than or equal to 8 \n" , n)
#define BIT_N(n) printf("%d is greater than 8 \n" , n)
#define BIT(n) ((n <= 8) ? (BIT_8(n)) : (BIT_N(n)))

int main() {
    BIT(7);
    BIT(8);
    BIT(9);
    return 0;
}


0 commentaires

1
votes

Le défi est que le pré-processeur ne connaît pas les mathématiques. Vous pouvez résoudre ce problème en implémentant les calculs dont vous avez besoin, mais cela devient MIDÉLANGÉ. Par exemple, voici le code pré-processeur de travail pour ce que vous voulez faire:

#include <stdio.h>

#define BIT_8(n) n, "is lower or equal than 8"
#define BIT_N(n) n, "is greater than 8"

// Identify values less than 8; make the second argument 8
#define LT_8_0 ~,8
#define LT_8_1 ~,8
#define LT_8_2 ~,8
#define LT_8_3 ~,8
#define LT_8_4 ~,8
#define LT_8_5 ~,8
#define LT_8_6 ~,8
#define LT_8_7 ~,8
#define LT_8_8 ~,8

// Helper macros.  Delays let arguments be processed before the macros is run.
#define MERGE(A, B) A ## B
#define MERGE_DELAY(A, B) MERGE(A,B)
#define ARG2(A,B,...) B
#define ARG2_DELAY(A,B,...) ARG2(A,B,__VA_ARGS__)

// Return 8 or N depending if n <= 8...
#define LT_8(n) ARG2_DELAY( MERGE(LT_8_, n), N,~ )

#define BIT(n) MERGE_DELAY(BIT_, LT_8(n))(n)

int main() {
  printf("%d %s\n", BIT(9));
  return 0;
}

Notez que la macro LT_8 fonctionne en prenant le deuxième d'une série d'arguments. Nous par défaut ce deuxième argument à N, mais si nous reconnaissons que le nombre d'entrée est 8 ou moins, nous insérons un nouveau deuxième argument de 8.


0 commentaires