在嵌入式系统编程 (C) 中,全局变量是否令人不悦?

Are global variables as frowned upon in embeded systems programming (C)?

我几年前了解到,在应用程序世界中,全局变量是"bad"或"frowned upon",因此尽量避免使用它们并很少使用它们已成为一种习惯。

在嵌入式世界中,当涉及到硬件中断时,它们几乎是不可避免的。它们也必须是可变的,这样如果编译器发现它们从未在 运行 程序中被触及,它就不会优化它们。

这两个说法都是真的吗?有没有办法在我描述的情况下避免这些变量而不向后弯曲太多?

Seems like that in the embedded world they are almost unavoidable when it comes to working with hardware interrupts. They also have to be made volatile so that the compiler does not optimize them out if it sees them never being touched in the running program.

Are both of these statements true ? is there a way to avoid those variables in the case I described without bending too far backward ?

这些说法都不正确。

首先,让我们澄清一下,全局变量是指具有外部链接的文件范围变量。这些是可以使用 extern 关键字或错误调用的变量。

关于第一个声明:

Seems like that in the embedded world they are almost unavoidable when it comes to working with hardware interrupts.

使用硬件中断时可以避免使用全局变量。正如其他人在评论中指出的那样,嵌入式环境中的全局变量并不少见,但也不鼓励使用它们,特别是如果您有能力实施适当的封装。 This article,有人在对你的问题的评论中提供,实际上包含一个 reader 响应,它提供了一个很好的例子,说明不可能正确实现封装的地方(你不必走得太远,这是第一个)。

关于第二种说法:

They also have to be made volatile so that the compiler does not optimize them out if it sees them never being touched in the running program.

这个说法,比方说'almost true'。编译器知道何时需要访问变量的内存位置(从内存写入 to/read),因此当打开优化时,它将避免不必要的内存访问。 volatile 关键字告诉编译器不要这样做,这意味着每次使用变量时都会访问该内存位置。

需要使用 volatile 关键字的情况

  • 全局变量更新中断
  • 多线程应用程序中多个线程访问的全局变量
  • 内存映射外设寄存器

对于通过中断更新的全局变量,volatile 关键字是必要的,因为中断随时可能发生,我们不想错过那个更新。 对于不被中断更新且应用程序是单线程的全局变量,volatile 关键字是完全不必要的,它实际上会减慢您的代码速度,因为您每次都将访问该变量的内存位置!

is there a way to avoid those variables in the case I described without bending too far backward ?

答案真的取决于。可能最重要的是您可以从进行此设计更改中获得什么?另外,这是一个专业项目,一个用于学校,还是一个娱乐?

根据我作为工程师的经验,上市时间往往是公司在开发新产品时最担心的事情。通常会有一些在研究和开发阶段开发的遗留代码让您陷入困境,而且 'works' 那么为什么要花时间修复未损坏的东西呢?说真的,最好是一个非常有说服力的论据,否则不要浪费你的时间。

根据我的教育经验,花时间回去实施正确的设计理念并记录下来绝对值得,但前提是您确实有时间这样做!如果您接近截止日期,请不要冒险。如果你领先于游戏,那就去做吧。它的价值不止一个。

最后,要正确封装硬件中断的中断服务程序 (ISR),您需要将其放置在实际的设备驱动程序(CAN、UART、SPI 等)中。与 ISR 的所有通信都应仅由设备驱动程序和设备驱动程序来促进。 ISR 和设备驱动程序之间共享的变量应声明为 staticvolatile。如果您需要从外部访问这些变量中的任何一个,您可以为驱动程序创建 setter 和 getter 作为 public API 的一部分。 Check this answer out for a general guideline to follow.