【问题标题】:C Macro - how to get an integer value into a string literal [duplicate]C宏-如何将整数值转换为字符串文字[重复]
【发布时间】:2017-03-28 05:48:19
【问题描述】:

是否可以将 #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
...
}

到目前为止,我已经尝试了所有我能想到的宏技巧(#stringification、arg 替换,甚至 #include 具有各种值组合和双引号之类的文件)。

我完全不熟悉将 AVR 汇编代码内联到 AVR Studio 的 GCC 编译器的神奇之处。

我试图避免在我的源代码中多次出现“48”字面值,如果预处理器可以为我执行这种替换,那就太好了。

编辑:这是一个微控制器固件项目 - 只是为了让生活变得有趣,几乎没有多余的空间可以添加新代码。

【问题讨论】:

  • 为什么字符串化和字符串连接不起作用?
  • @CodyGray,字符串化不会“评估”您传入的内容,它只是获取参数中的字符并将它们直接转储出 vrbatim,除非您在字符串化之前使用额外的宏替换所需的字符.
  • 这怎么不是重复的?我认为@CodyGray 和 PSkocik 的回答中建议的双宏技术是众所周知的,所以肯定以前有人问过。 (不过,对于这个问题,现在这是一个很好的规范问答,所以不太清楚的问题和不太好的答案可能会被标记为重复。)

标签: c gcc assembly c-preprocessor avr


【解决方案1】:

您需要两个辅助宏才能使其工作。然后您可以利用自动字符串连接:

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

【讨论】:

    【解决方案2】:

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

    这依赖于相邻字符串文字被连接的事实。

    【讨论】:

    • 这是我回答的更好版本。赞成。
    • 啊,是的,这似乎可以解决问题。我想我有类似的东西,但我的#defines 是低音。太棒了。
    【解决方案3】:

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

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

    【讨论】:

    • 有趣。此页面看起来相关:gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html。在这种情况下,我将坚持使用讨厌的宏,因为 C 程序员更容易理解它(有点!)。
    • @Wossname:你将如何使用“基本”asm(没有约束)而不踩到编译器的脚趾(即在不告诉它的情况下破坏寄存器)?请参阅inline assembly tag wiki 了解更多信息。 “扩展”asm 是使用它的正常方式,而 AFAIK 是唯一安全的方式,不仅可以使用不影响寄存器的指令(例如内存栅栏或其他东西)。
    • @PeterCordes,我使用 ASM 只是为了在关键时间范围内完成必要的指令。一旦 ASM 返回到 C 代码,ASM 中使用的所有内存都会重新初始化。汇编器输出表明这不会成为问题。但是你提出这一点是对的,如果我养成使用 AVR 汇编的习惯(不太可能),那么我肯定会研究正确的做事方式。就目前而言,最糟糕的事情是我的圣诞树会停止闪烁几秒钟。 :)
    • @Wossname:我说的是寄存器,而不是内存。假定“基本”asm 语句不会破坏任何寄存器,因此如果您在启用优化的情况下进行编译,您的代码将很容易中断。 (如果你不这样做......为什么不这样做,尤其是在空间紧张的情况下?)如果你真的拒绝正确地这样做,那么使用没有任何输入/输出操作数的扩展 asm,但这会声明一个 clobber on您接触的每个 reg。 asm("..." : : : "r18", "r19", "r20" );
    • 我会稍微研究一下并相应地更新我的问题。
    猜你喜欢
    • 1970-01-01
    • 2022-08-05
    • 2011-08-22
    • 2012-06-28
    • 2016-03-16
    • 2010-10-05
    • 1970-01-01
    • 2013-10-06
    相关资源
    最近更新 更多