中断服务处理程序的代码:
volatile unsigned char x = 0;
void interruptHandler() __attribute__ ((signal));
void interruptHandler() {
f();
g();
}
呼叫:
void f() { x ++; } // could be more complex, could also be in a different file
void g() { x ++; } // as `f()`, this is just a very simple example
因为x
是一个易变量变量,所以每次使用它都会被读取和写入。中断处理程序的主体编译为(avr-gcc -g -c -Wa,-alh -mmcu=atmega328p -Ofast file.c
):
lds r24,x
subi r24,lo8(-(1))
sts x,r24
lds r24,x
subi r24,lo8(-(1))
sts x,r24
现在我可以手动内联函数并使用临时变量:
unsigned char y = x;
y ++;
y ++;
x = y;
或者我可以写:
x += 2;
两个示例都编译得更有效:
lds r24,x
subi r24,lo8(-(2))
sts x,r24
是否可以告诉avr-gcc
优化对interruptHandler
内部易变变量的访问,即自动进行手动优化?
毕竟,当interruptHandler
正在运行时,全局中断被禁用,x
无法更改。我不想手动优化代码,因此可能会创建重复的代码(如果在其他地方需要f()
和g()
)并引入错误。
答案 0 :(得分:1)
是否可以告诉avr-gcc优化对interruptHandler内部的volatile变量的访问,即自动进行手动优化?
不,这在C语言中是不可能的。
毕竟,当interruptHandler正在运行时,全局中断被禁用
编译器不知道这一点 - 你可以简单地将sei
放入处理程序中以重新打开它们。
另请注意,硬件寄存器也被声明为volatile
。其中一些 - 如UART数据寄存器 - 即使在读取时也会产生副作用。编译器不得删除任何读取或写入。
答案 1 :(得分:0)
如果您声明变量是易失性的,则对它的所有访问都是易失性的-编译器将按照源代码的说明准确地读写该变量,而无需组合它们或进行类似的优化。
因此,如果您要组合优化,则声明变量时不要使用“ volatile”-那么您将在中断代码中获得所需的内容。
然后从中断代码之外,您可以使用以下宏来强制进行易失性访问:
#define volatileAccess(v) *((volatile typeof((v)) *) &(v))
在中断代码外使用“ volatileAccess(x)”而不是“ x”。
别忘了“挥发”并不意味着“原子”!