web-dev-qa-db-fra.com

C Macro - comment obtenir une valeur entière dans un littéral de chaîne

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

Je veux que les "LEDS" soient remplacées par 48 dans le littéral de chaîne à l'intérieur 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 (une fois que le préprocesseur a fait son travail) voit cela ...

#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'arguments et même #inclusion de fichiers avec diverses combinaisons de valeurs et de guillemets doubles et ainsi de suite).

Je ne connais pas du tout la magie de l'inclusion du code AVR Assembly 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: c'est pour un projet de firmware de microcontrôleur - et juste pour rendre la vie intéressante, il n'y a presque pas de place de rechange pour le nouveau code à ajouter.

32
Wossname

Je pense que c'est bien d'avoir une macro stringifiante dans votre en-tête utils:

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

Ensuite, vous pouvez 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"
...
}

Les pré-processus ci-dessus pour:

int x = 48;

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

qui repose sur le fait que les littéraux de chaîne adjacents sont concaténés.

46
PSkocik

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

#define LEDS 48

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

Vous avez besoin de deux macros auxiliaires pour que cela fonctionne. Ensuite, vous pouvez profiter de la concaténation automatique des chaînes:

#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 transmis.

Si vous venez de faire ceci:

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

Il s'élargirait à ceci:

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

La macro EXPAND permet également de remplacer le paramètre transmis.

Alors ceci:

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

Serait élargi à ceci:

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