C: 将 static volatile 与 "getter" 函数和中断一起使用
C: Using static volatile with "getter" function and interruptions
假设我有以下 C 代码:
/* clock.c */
#include "clock.h"
static volatile uint32_t clock_ticks;
uint32_t get_clock_ticks(void)
{
return clock_ticks;
}
void clock_tick(void)
{
clock_ticks++;
}
现在我在中断内调用 clock_tick
(即:递增 clock_ticks
变量),同时从 main()
函数调用 get_clock_ticks()
(即:在中断外).
我的理解是 clock_ticks
应该被声明为 volatile
否则编译器可以优化它的访问并使 main()
认为值没有改变(而它实际上从中断)。
我想知道在那里使用 get_clock_ticks(void)
函数,而不是直接从 main()
访问变量(即:不将其声明为 static
)是否真的可以强制编译器加载来自内存的变量,即使它没有声明为 volatile。
我想知道有人告诉我这可能会发生。是真的吗?在什么条件下?不管我是否使用 "getter" 函数,我都应该始终使用 volatile
吗?
getter 函数在这里对使用 volatile
没有任何帮助。
- 假设编译器发现您刚刚获取了上面两行的值并且此后没有更改它。
- 如果它是一个很好的优化编译器,我希望它看到函数调用没有副作用,只需优化函数调用即可。
如果 get_clock_ticks()
会是 external
(即在一个单独的模块中),情况就不同了(也许这就是你记得的)。
可以在正常程序流程之外(例如在 ISR 中)更改其值的东西,应该 始终 声明 volatile
。
不要忘记,即使您当前编译声明 get_clock_ticks 的代码和使用它作为单独模块的代码,也许有一天您会使用 link-时间或跨模块优化.即使您使用的是 getter 函数,也要保留 "volatile" - 在这种情况下,它不会对代码生成造成任何损害,并使代码正确。
你没有提到的一件事是处理器的位大小。如果它不能在单个操作中读取 32 位值,那么您的 get_clock_ticks() 有时会失败,因为读取不是原子的。
假设我有以下 C 代码:
/* clock.c */
#include "clock.h"
static volatile uint32_t clock_ticks;
uint32_t get_clock_ticks(void)
{
return clock_ticks;
}
void clock_tick(void)
{
clock_ticks++;
}
现在我在中断内调用 clock_tick
(即:递增 clock_ticks
变量),同时从 main()
函数调用 get_clock_ticks()
(即:在中断外).
我的理解是 clock_ticks
应该被声明为 volatile
否则编译器可以优化它的访问并使 main()
认为值没有改变(而它实际上从中断)。
我想知道在那里使用 get_clock_ticks(void)
函数,而不是直接从 main()
访问变量(即:不将其声明为 static
)是否真的可以强制编译器加载来自内存的变量,即使它没有声明为 volatile。
我想知道有人告诉我这可能会发生。是真的吗?在什么条件下?不管我是否使用 "getter" 函数,我都应该始终使用 volatile
吗?
getter 函数在这里对使用 volatile
没有任何帮助。
- 假设编译器发现您刚刚获取了上面两行的值并且此后没有更改它。
- 如果它是一个很好的优化编译器,我希望它看到函数调用没有副作用,只需优化函数调用即可。
如果 get_clock_ticks()
会是 external
(即在一个单独的模块中),情况就不同了(也许这就是你记得的)。
可以在正常程序流程之外(例如在 ISR 中)更改其值的东西,应该 始终 声明 volatile
。
不要忘记,即使您当前编译声明 get_clock_ticks 的代码和使用它作为单独模块的代码,也许有一天您会使用 link-时间或跨模块优化.即使您使用的是 getter 函数,也要保留 "volatile" - 在这种情况下,它不会对代码生成造成任何损害,并使代码正确。
你没有提到的一件事是处理器的位大小。如果它不能在单个操作中读取 32 位值,那么您的 get_clock_ticks() 有时会失败,因为读取不是原子的。