web-dev-qa-db-fra.com

Une définition de macro C peut-elle faire référence à d'autres macros?

Ce que j'essaie de comprendre, c'est si quelque chose comme ça (écrit en C ):

#define FOO 15
#define BAR 23
#define MEH (FOO / BAR)

est autorisée? Je voudrais que le préprocesseur remplace chaque instance de

MEH

avec

(15 / 23)

mais je ne suis pas sûr que cela fonctionnera. Certes, si le préprocesseur ne passe en revue le code qu'une seule fois, je ne pense pas que cela fonctionnerait comme je le voudrais.

J'ai trouvé plusieurs exemples similaires mais tous étaient vraiment trop compliqués à comprendre. Si quelqu'un pouvait m'aider avec ce simple, je serais éternellement reconnaissant!

38
llakais

Réponse courte oui. Vous pouvez imbriquer des définitions et des macros comme ça - autant de niveaux que vous le souhaitez tant que ce n'est pas récursif.

33
Mysticial

La réponse est "oui", et deux autres personnes l'ont correctement dit.

Quant à pourquoi la réponse est oui, les détails sanglants sont dans norme C , section 6.10.3.4, "Nouvelle analyse et remplacement ultérieur". Le PO pourrait ne pas en bénéficier, mais d'autres pourraient être intéressés.

6.10.3.4 Nouvelle analyse et remplacement supplémentaire

Une fois que tous les paramètres de la liste de remplacement ont été remplacés et que le traitement # et ## a eu lieu, tous les jetons de prétraitement des repères sont supprimés. Ensuite, la séquence de jetons de prétraitement résultante est analysée à nouveau, ainsi que tous les jetons de prétraitement ultérieurs du fichier source, pour plus de noms de macro à remplacer.

Si le nom de la macro en cours de remplacement est trouvé lors de cette analyse de la liste de remplacement (à l'exclusion du reste des jetons de prétraitement du fichier source), il n'est pas remplacé. En outre, si des remplacements imbriqués rencontrent le nom de la macro en cours de remplacement, il n'est pas remplacé. Ces jetons de prétraitement de nom de macro non remplacés ne sont plus disponibles pour un remplacement ultérieur même s'ils sont (ré) examinés ultérieurement dans des contextes dans lesquels ce jeton de prétraitement de nom de macro aurait sinon été remplacé.

La séquence de jetons de prétraitement complètement remplacée par macro résultante n'est pas traitée comme une directive de prétraitement même si elle en ressemble une, mais toutes les expressions d'opérateur unaire pragma qu'elle contient sont ensuite traitées comme spécifié au 6.10.9 ci-dessous.

27
Keith Thompson

Oui, ça va marcher.


Mais pour vos informations personnelles, voici quelques règles simplifiées sur les macros qui pourraient vous aider (elles sont hors de portée, mais vous aideront probablement à l'avenir). Je vais essayer de le garder aussi simple que possible.

  • Les définitions sont "définies" dans l'ordre où elles sont incluses/lues. Cela signifie que vous ne pouvez pas utiliser une définition qui n'a pas été définie précédemment.

  • Mot-clé préprocesseur utile: #define, #undef, #else, #Elif, #ifdef, #ifndef, #if

  • Vous pouvez utiliser n'importe quel autre #define précédemment dans votre macro. Ils seront élargis. (comme dans votre question)

  • Les définitions de macro de fonction acceptent deux opérateurs spéciaux (# et ##)

operator # stringize l'argument:

#define str(x) #x
str(test); // would translate to "test"

l'opérateur ## concatène deux arguments

#define concat(a,b) a ## b
concat(hello, world); // would translate to "helloworld"

Il existe également des macros prédéfinies (à partir de la langue) que vous pouvez utiliser:

__LINE__, __FILE__, __cplusplus, etc

Voir votre section compilateur à ce sujet pour avoir une liste complète car ce n'est pas "multi-plateforme"

  • Faites attention à l'expansion macro

Vous verrez que les gens utilisent un journal de parenthèses rondes "()" lors de la définition des macros. La raison en est que lorsque vous appelez une macro, elle est développée "en l'état"

#define mult(a, b) a * b
mult(1+2, 3+4); // will be expanded like: 1 + 2 * 3 + 4 = 11 instead of 21.
mult_fix(a, b) ((a) * (b))
14
Sauleil

Je voudrais ajouter un piège qui m'a fait trébucher.

Les macros de style fonction ne peuvent pas faire cela.

Exemple qui ne compile pas lorsqu'il est utilisé:

#define FOO 1
#define FSMACRO(x) FOO + x
2
Stefan Monov

Oui, cela est pris en charge. Et utilisé beaucoup!

Une chose importante à noter est de vous assurer que vous parenthèses l'expression sinon vous pourriez rencontrer des problèmes désagréables!

#define MEH FOO/BAR

// vs

#define MEH (FOO / BAR)

// the first could be expanded in an expression like 5 * MEH to mean something 
//   completely different than the second
0
Mike Dinescu