中断服务处理程序的代码:
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
内部的volatile变量的访问,即自动进行手动优化?
毕竟,当 interruptHandler
正在运行时,全局中断被禁用, x
无法更改 . 我更喜欢不必手动优化代码,从而可能创建重复的代码(如果在别处需要 f()
和 g()
)并引入错误 .
2 回答
不,这在C语言中是不可能的 .
编译器不知道这一点 - 您可以简单地将
sei
放入处理程序中以重新打开它们 .另请注意,硬件寄存器也声明为
volatile
. 其中一些 - 如UART数据寄存器 - 即使在读取时也会产生副作用 . 编译器不得删除任何读取或写入 .如果将变量声明为volatile,则对它的所有访问都是易失性的 - 编译器将完全读取和写入源代码所说的次数,而不是将它们组合或进行类似的优化 .
因此,如果您想要组合优化,声明变量而不使用“volatile” - 那么您将在中断代码中获得所需的内容 .
然后从中断代码外部,你可以使用像这样的宏来强制进行易失性访问:
在中断代码之外使用“volatileAccess(x)”而不是“x” .
只是不要忘记“挥发性”并不意味着“原子”!