【发布时间】:2021-12-27 00:57:51
【问题描述】:
我多次听说,如果不谨慎使用全局变量可能是“危险的”。保护全局变量(或指示读者与哪些代码段相关)的一种方法是使用 struct 并将所有全局变量作为成员放入其中。
术语“全局保护”是指无法从某个 xxx 源文件中意外修改全局值。使用 struct,您可以向读者(或您自己)阐明这个全局结构的成员可能在哪里使用,因此变量功能的不确定性更少。
我尝试在我的项目中实现这一点,我认为这是一个好主意,因为我计划在未来使用更多的 ISR。为了防止意图不明或代码错误,使用了全局变量保护的上层方法。但得出的结论是,如果必须在 struct 内部访问 struct,那么新的变量组织看起来会更糟,因为代码可读性在很大程度上降低了(我的观点)。
这是我用于按钮去抖动的代码的 sn-p。异或两个成员看起来像一条讨厌的长“蛇”,但如果不需要某些变量组织(内部结构),则可以写为change = new ^ old。
/*** HEADER FILE ***/
/** Button state structure **/
typedef struct {
uint16_t old;
uint16_t new;
uint16_t change;
} state;
/** Protect ISR globals within structure **/
typedef struct {
state buttonState;
uint16_t isPortStable;
uint16_t countStableStates[BTN_COUNT];
uint32_t tick;
} debounceISR;
debounceISR DB; // !! Keep struct name short to affect readability as little as possible !!
/*** SOURCE FILE ***/
/* Read keyboard and check for transitions */
DB.buttonState.new = BTN_PORT;
DB.buttonState.change = DB.buttonState.new ^ DB.buttonState.old;
DB.buttonState.old = DB.buttonState.new;
从长远来看,我想防止全局变量在用户(编码器)不知情的情况下进行干扰,并在一个项目中随着 ISR(以及全局变量)数量的增加而导致复杂的问题。
对于此类需求,是否有其他选择?在使用 ISR 时,我是否应该倾向于使用指针和静态变量以避免全局变量?
【问题讨论】:
-
我从来没有听说过让全局结构的全局成员来缓解与全局相关的问题。我想这样做可以解决大多数与全局变量相关的命名空间问题,但我从未认为这些是主要问题。
-
在适当的时候使用全局变量并没有错。当然,如果您可以限制它们的范围(通过将它们标记为
static)然后这样做,它将防止在其他翻译单元中“干扰”它们。 -
我不会说全局变量是“危险的”。它们可能令人困惑,尤其是当你有很多它们时,尤其是当它们同时从代码的多个不同部分读取和写入时。没有针对全局变量的规则(在大多数人的风格指南中);只是建议谨慎使用它们,并且仅在需要时使用。
-
@Keno 如何使用指针... 你可以这样做。我已经做到了。这不是一个坏主意,但我也不会说这是一个超级好主意。从“穷人的命名空间”开始,它有点像“穷人的封装类”,尽管没有 getter 和 setter 的好处。它可能会为您买一点,也可能会花费您一点。
-
@Keno 最后,我的cmets都是从“高级”程序员的角度出发的。我的代码从来没有 ISR,所以我不必担心如何与它们通信,或者全局变量是否是这样做的好/坏方法。对于嵌入式编程,许多“规则”略有不同或显着不同。这里有很多嵌入式 C 程序员;您可能(可能?)通过添加 [embedded] 标签更有效地采纳他们的建议。
标签: c struct embedded global-variables isr