2016-11-14 64 views
30

是否有可能得到一个#defined 整数符号被逐字地插入到字符串文本中,该文字是GCC中的汇编部分的一部分(AVR工作室)?C宏 - 如何获得一个整数值到字符串文字

我想在下面的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替换,甚至#including具有各种值和双引号组合的文件以及什么)。

我完全不熟悉将AVR汇编代码内联到AVR Studio的GCC编译器中的魔力。

我试图避免在我的源文件中出现多次出现的“48”文字,如果预处理器可以对我进行这种替换,那会很棒。

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

+0

看看[放置一个预处理指令字符串文字内(http://stackoverflow.com/q/14721007/ 2305521) – fpg1503

+2

为什么不进行字符串化和字符串连接? –

+0

@CodyGray,字符串化不会“评估”你传入的内容,它只是取参数中的字符并将它们直接从vrbatim转储出来,除非在字符串化之前使用额外的宏来替换所需的字符。 – Wossname

回答

46

我认为这是件好事,在你的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" 
... 
} 

它依赖于一个事实,即相邻的字符串字面量得到串联。

+4

这是我的答案的更好的版本。 Upvoted。 – 2501

+0

啊,是的,这似乎是伎俩。我想我有类似的东西,但我的#定义是低音赞赏。灿烂。 – Wossname

13

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

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

可以避开字串宏一塌糊涂,如果你使用的约束:

#define LEDS 48 

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

有趣。此页面看起来相关:https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html。在这种情况下,我会坚持使用令人讨厌的宏,因为它更容易被C程序员理解(有点!)。 – Wossname

+2

@Wossname:你如何在没有踩到编译器的脚趾的情况下使用“basic”asm(没有约束)(即没有告诉它的翻转寄存器)?查看[inline assembly tag wiki](http://stackoverflow.com/tags/inline-assembly/info)了解更多信息。 “扩展”asm是使用它的常用方式,AFAIK是唯一安全的方式,而不是使用不影响寄存器的指令(例如内存围栏或其他)。 –

+0

@PeterCordes,我只使用ASM来获得在关键时间框架内完成的必要指示。一旦ASM返回到C代码,ASM中使用的所有内存都将重新初始化。汇编输出表明在这不会是一个问题。但是你提出这一点是正确的,如果我养成了使用AVR组装的习惯(不太可能),那么我肯定会研究正确的做法。就目前来看,最糟糕的情况是我的圣诞树会停止闪烁几秒钟。 :) – Wossname

相关问题