我在ATmega微控制器的C程序中有以下代码:
define sbi(port,bit) asm("SBI " #port "," #bit)
[...]
sbi(PORTB,1);
问题是编译器在处理程序集代码时无法识别PORTB,尽管它是在包含的头文件中定义的。有没有一种方法可以告诉预编译器将定义的PORTB(0x1b(值放在ASM指令中,而不是文本PORTB?当我手动这样做时,组装说明工作正常:
sbi(0x1b,1);
但出于显而易见的原因,我希望能够在C代码中使用PORTB和其他定义的名称。
请注意,我只将这个ASM宏用于定义的常量,而不是变量,所以我不需要任何太花哨的东西来桥接我的ASM宏和C代码。我只需要预处理器将ASM字符串中的PORTB替换为0x1b。
通常不应使用字符串化(宏#
运算符(为asm
构造构造字符串。相反,请使用扩展的asm
语法。
要将操作数放入汇编指令中,请将该语法与约束一起使用,这些约束告诉编译器如何将操作数提供给指令。对于立即数操作数,请使用i
:
asm("SBI %[port], %[bit]"
: // Output operands would be here.
: // Input operands are here.
[port] "i" (PORT),
[bit] "i" (1)
);
指令字符串中的%[port]
将替换为名为port
的操作数。稍后操作数列表中的[port]
表示该操作数的名称为port
。当然,除了大小写之外,这与PORT
匹配,但您可以使用其他名称。
"i"
表示要使用立即数操作数,该操作数必须具有编译时常数值。
(PORT)
中的PORT
是一个表达式,用于给出操作数的值。例如,您也可以使用(PORT+1)
。
1
操作数可以是硬编码的,但上面展示了如何保持它的灵活性。
对于具有i
的默认立即数操作数,GCC和Clang包括在汇编代码中标记立即数操作的标点符号,例如某些汇编程序中的$
。如果由于某种原因这是一个问题,可以使用%c[port]
而不是%[port]
来获得裸操作数,并手动插入#
,如:
asm("SBI #%c[port], #%c[bit]"
: // Output operands would be here.
: // Input operands are here.
[port] "i" (PORT),
[bit] "i" (1)
);