C宏-如何将整数值转换为字符串[duplicate]

bvjxkvbb  于 2023-01-29  发布在  其他
关注(0)|答案(3)|浏览(131)
    • 此问题在此处已有答案**:

Stringification of a macro value(3个答案)
六年前关闭了。
是否可以获得#defined * integer * 符号的值,并将其逐字插入到GCC(AVR Studio)中汇编部分的字符串文本中?
我希望在下面的asm()代码块中的字符串文字中将"LEDS"替换为48。

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

到目前为止,我已经尝试了我能想到的所有宏技巧(#字符串化、arg替换,甚至#包含值和双引号的各种组合的文件等等)。
我一点也不熟悉将AVR汇编代码内联到AVR Studio的GCC编译器中的神奇之处。
我试图避免在源代码中多次出现"48"字面值,如果预处理器可以为我执行这个替换,那就太好了。
编辑:这是为一个微控制器固件项目-而且只是为了让生活变得有趣,几乎没有多余的空间来添加新的代码。

qpgpyjmq

qpgpyjmq1#

我认为在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"
...
}

这依赖于相邻字符串文字被连接的事实。
或者,您可以创建一个允许使用逗号的STR宏:

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

然后使用它将整个asm主体字符串化,如下所示:

asm( STR(
    ldi        R27, 0x00;
    ldi        R26, 0x00;
    ldi        R18, LEDS; //LEDS gets expanded
)); //renders: "ldi R27, 0x00; ldi R26, 0x00; ldi R18, 48;"

(就我个人而言,我在clang/gcc/tinycc上这样写asm,因为我发现它比显式字符串常量更方便)这种方法有一个潜在的缺点,即汇编程序只有一行,并且只要汇编程序除了换行符之外还接受;作为指令分隔符,就可以进行汇编(至少对clang/gcc/tinycc上的x86-64汇编程序有效)。

k4ymrczo

k4ymrczo2#

如果使用一个约束,就可以避免字符串化宏的混乱:

#define LEDS 48

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

sxpgvts33#

你需要两个辅助宏来完成这个操作,然后你可以利用自动字符串连接:

#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");

相关问题