32 votes

Macro C - comment transformer un entier en chaîne de caractères ?

Est-il possible d'obtenir la valeur d'un #defined entier à insérer textuellement dans une chaîne littérale qui fait partie d'une section d'assemblage dans GCC (AVR Studio) ?

Je veux que le "LEDS" soit remplacé par 48 dans la chaîne littérale du bloc asm() ci-dessous.

#define LEDS 48 //I only want ONE mention of this number in the source
int x = LEDS;   //I'm using the value directly too

void DrawFrame()
{
    asm(
    "ldi        R27, 0x00       \n\t"
    "ldi        R26, 0x00       \n\t"
    "ldi        R18, LEDS       \n\t" //<-- substitution needed here
...
}

Mais je veux que le compilateur/assembleur (après que le préprocesseur ait fait son travail) voit ceci...

#define LEDS 48 //I only want ONE mention of this number in the source
int x = LEDS;   //I'm using the value directly too

void DrawFrame()
{
    asm(
    "ldi        R27, 0x00       \n\t"
    "ldi        R26, 0x00       \n\t"
    "ldi        R18, 48         \n\t" //<-- substitution needed here
...
}

Jusqu'à présent, j'ai essayé toutes les astuces de macro auxquelles je peux penser (#stringification, substitution d'arg et même #inclusion de fichiers avec diverses combinaisons de valeurs et de guillemets et ainsi de suite).

Je ne suis pas du tout familier avec la magie de l'inlining du code d'assemblage AVR dans le compilateur GCC d'AVR Studio.

J'essaie d'éviter d'avoir plusieurs occurrences du littéral "48" dans ma source. Si le préprocesseur peut effectuer cette substitution pour moi, ce serait formidable.

Edit : Ceci est pour un projet de microcontrôleur firmware - et juste pour rendre la vie intéressante, il n'y a presque pas de place libre pour l'ajout de nouveau code.

47voto

ThorX89 Points 967

Je pense qu'il est bon d'avoir une macro de stringification dans votre en-tête utils :

#define STR_IMPL_(x) #x      //stringify argument
#define STR(x) STR_IMPL_(x)  //indirection to expand argument macros

Vous pouvez alors conserver la macro numérique et la stringifier sur place :

#define LEDS 48 
int x = LEDS;   

void DrawFrame()
{
    asm(
    "ldi        R27, 0x00       \n\t"
    "ldi        R26, 0x00       \n\t"
    "ldi        R18, "STR(LEDS)"       \n\t"
...
}

Ce qui précède est prétraité pour :

int x = 48;

void DrawFrame()
{
    asm(
    "ldi        R27, 0x00       \n\t"
    "ldi        R26, 0x00       \n\t"
    "ldi        R18, ""48""       \n\t"
...
}

qui s'appuie sur le fait que les chaînes littérales adjacentes sont concaténées.

14voto

Jester Points 15625

Vous pouvez éviter le désordre de la macro de stringification si vous utilisez une contrainte :

#define LEDS 48

void DrawFrame()
{
    asm volatile(
    "ldi R18, %[leds]"
    : : [leds] "M" (LEDS) : "r18");
}

13voto

dbush Points 8590

Vous avez besoin de deux macros auxiliaires pour que cela fonctionne. Vous pouvez alors profiter de la concaténation automatique des chaînes de caractères :

#define STR(x) #x
#define EXPAND(x) STR(x)

#define LEDS 48
int x = LEDS;

void DrawFrame()
{
    asm(
    "ldi        R27, 0x00       \n\t"
    "ldi        R26, 0x00       \n\t"
    "ldi        R18, " EXPAND(LEDS) "       \n\t"
...
}

La raison de l'utilisation de deux macros est que la première seule ne développera pas le paramètre passé.

Si tu viens de faire ça :

printf("LEDS = " STR(LEDS) "\n");

Il s'étendrait à ceci :

printf("LEDS = " "LEDS" "\n");

Le site EXPAND permet également de substituer le paramètre passé.

Et puis ça :

printf("LEDS = " EXPAND(LEDS) "\n");

S'étendrait à cela :

printf("LEDS = " "48" "\n");

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X