【发布时间】:2018-11-09 05:37:15
【问题描述】:
中断服务处理程序代码:
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是一个volatile变量,所以每次使用都会读写。中断处理程序的主体编译为 (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())并引入错误。
【问题讨论】:
-
我可能在这里遗漏了一些东西,但如果 x 没有改变,你为什么不做
x += 2? -
在临时变量
y中计算x的新值有什么丑陋和困惑?只需添加一条注释,说明您正在使用临时变量y以防止多次读取 volatile 变量x。 -
我也遇到过类似的情况。我有一个定时器中断例程,它增加全局滴答计数,声明为易失性。该变量还在 ISR 内部用于其他目的。在我引入滴答计数的本地副本之前,编译器发出了低效的代码。我不知道具有变量的易失性和非易失性版本的联合是否可以工作,但会使代码不可读。使用本地副本,让编译器完成优化工作。
-
编译器正在以优化的方式执行您告诉它的操作。您拥有的两个示例不一样,编译器也不能对它们进行相同的解释。如果您想要这样的优化,您需要像您所展示的那样自己做,而不是编译器可以根据您使用的语言做的事情。如果你想要 volatile,你会得到 volatile(希望如此)如果你不想要 volatile 行为,那么不要将其声明为 volatile,以其他方式解决它。
-
@kkrambo 我在示例中略微增加了复杂性。即使中断处理程序中的代码编译成几十条指令,它也可能分布在不同的函数中以提高可读性。在这种情况下,很难使用临时变量。而且,除此之外,我更喜欢编译器自己做一些事情。
标签: gcc optimization microcontroller volatile avr-gcc