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" в моем источнике, если препроцессор может выполнить эту замену для меня, что было бы здорово.
Изменить: это для микропрограммного прошивки - и просто для того, чтобы сделать жизнь интересной, почти нет свободного места для добавления нового кода.
Ответы
Ответ 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");