Подтвердить что ты не робот

C Macro - как получить целочисленное значение в строковый литерал

Возможно ли, чтобы значение целочисленного символа #defined было вставлено дословно в строковый литерал, который является частью раздела сборки в GCC (AVR Studio)?

Я хочу, чтобы "LEDS" был заменен на 48 внутри строкового литерала внутри блока asm() ниже.

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

Но я хочу, чтобы компилятор/ассемблер (после того, как препроцессор выполнил это задание), чтобы увидеть это...

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

До сих пор я пробовал все макро-трюки, о которых я могу думать (#stringification, arg substitution и даже #include файлы с различными комбинациями значений и двойных кавычек и еще чего-то).

Я совсем не знаком с магией встраивания кода сборки AVR в компилятор AVR Studio GCC.

Я пытаюсь избежать наличия нескольких экземпляров литерала "48" в моем источнике, если препроцессор может выполнить эту замену для меня, что было бы здорово.

Изменить: это для микропрограммного прошивки - и просто для того, чтобы сделать жизнь интересной, почти нет свободного места для добавления нового кода.

4b9b3361

Ответ 1

Мне кажется, что в заголовке utils есть строгий макрос:

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

Затем вы можете удерживать макрос в числовом и строчить его на месте:

#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"
...
}

Вышеупомянутые препроцессы:

int x = 48;

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

который опирается на тот факт, что смежные строковые литералы объединяются.

Ответ 2

Вы можете избежать беспорядка макросов строения, если используете ограничение:

#define LEDS 48

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

Ответ 3

Для этого вам нужны два вспомогательных макроса. Затем вы можете воспользоваться автоматической конкатенацией строк:

#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"
...
}

Причиной использования двух макросов является то, что первый только не расширит передаваемый параметр.

Если вы только что сделали это:

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

Он будет расширяться до этого:

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

Макрос EXPAND позволяет заменять параметр, который должен быть заменен.

Итак, тогда:

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

Расширится до этого:

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