2

在处理微控制器时,有些东西本质上是全球性的——我正在考虑诸如串行端口或其他接口之类的外围设备。还有一些外设不仅是全局的,而且只有一个(而且永远不会更多)——比如控制核心时钟或中断控制器的外设。这些外设确实具有某种全局状态(例如 - 核心时钟设置为某个值)并且反向计算这些值效率低下。

需要设置 RTOS 使用的系统定时器,需要设置其他外设的时钟(UART 波特率,SPI 比特率,...),需要为外部存储器设置正确的时钟或配置存储器等待状态。这就是为什么我认为在 main() 中创建一个对象并将其传递到任何地方会有点麻烦......

我可以编写方法,以便所有“全局”信息都来自外围寄存器(例如,可以从当前 PLL 设置反向计算核心频率),但这似乎也是一个错误的想法,更不用说创建对象了对于时钟发生器外设,到处都会看起来很有趣......

当前时钟设置可以存储在该类的静态成员中,但是从这里开始,只有一小步迈向完全静态的类(因为“this”指针对于没有状态的类将毫无用处)......

通常在非面向对象程序中找到的解决方案最接近于完全静态的类——只有对全局变量进行操作的函数。

任何人都知道如何很好地处理这种情况,或者这个问题是否值得花时间?也许我应该只使用一个全局对象并完成它?(;

4

4 回答 4

5

如果我希望我的程序很好地面向对象,我很难决定如何处理这些对象......全局变量不好,这很明显,但我只是不知道(还不够经验)我是否应该尝试“隐藏”这些事情是全球性的事实......

当我读到这篇文章时,我想知道您是否知道为什么要使用 OOP 以及为什么不使用全局变量。

首先,OOP 是一个工具,而不是一个目标。在您的情况下,中断控制器不需要派生和虚拟功能之类的东西。您所需要的只是一个对其进行编程的接口,封装在一个类中。你甚至可以使用一组简单的函数来做到这一点(C=风格模块化编程),而不会放弃可维护性。在您的情况下,使单个实例全局化更加清晰。想象一下替代方案,程序的不同部分可以实例化一个用于访问下面相同的 UART 的类。如果您使用全局变量,代码(或者更确切地说是作者)会意识到这一点,并会考虑如何协调访问。

现在,关于全局变量,这里有一个为什么不使用它们的例子:

int a, b, c;

void f1()
{
    c = a;
    f3();
}

void f2()
{
    c = b;
    f3();
}

void f3()
{
    // use c
}

int main()
{
    a = 4;
    f1();
    b = 5;
    f2();
}

这里的要点是,参数存储在全局变量中,而不是作为实际参数传递,因此很难看到它们的使用地点和时间。此外,上述使用完全排除了任何递归调用。关于您的环境,有些东西本质上是全局的,因为它们是环境的独特部分,例如中断控制器(类似于 cin/cout/cerr/clog)。不要担心那些。在您需要考虑限制访问之前,必须在整个地方使用它们中的许多。

有两个准则可以使这更容易:

  • 一个对象的范围越大,它就越需要一个会说话的名字(对比上面的 a、b、c)。在您的情况下,我会将所有特定于硬件的对象存储在一个公共命名空间中,因此很明显某些代码正在访问全局变量。这也允许单独测试和重用这个命名空间。许多硬件供应商甚至以库的形式提供类似的东西,以帮助应用程序开发。
  • 在封装/建模硬件的代码中,执行请求,但不要做出特定于其之上的应用程序的决策。与标准库本身提供但从未使用过的标准流进行比较,除了可能用于在断言失败后中止之前转储致命错误信息。
于 2013-04-07T08:32:36.337 回答
2

毫无疑问,单例模式是争论的焦点。有些人只是说它“不好”,但我不同意;它只是被广泛滥用和误解。它在某些情况下绝对有用。事实上,它完全适用于你所描述的情况。

如果您有一个需要全局可用的类,并且本质上不能有多个实例,那么单例是最好的选择。

于 2013-04-07T07:58:27.570 回答
2

您已经大致概述了您的选择:

  • 全局变量
  • 类/单例的静态数据成员

最终取决于您在两者之间做出决定,并从美学或其他角度选择您更喜欢的。

归根结底,正如您所说,您仍将拥有一个时钟发生器、一个 UART 等。

要记住的一件事是,仅仅为了抽象目的而进行过多的抽象不会给你带来太多好处。然而,它可能做的是让不熟悉您的代码的人更难弄清楚事情是如何在类层后面真正工作的。因此,如果有的话,请考虑您的团队。

于 2013-04-07T07:55:54.243 回答
1

单例、全局对象、静态类,它们都是一样的。用你想要的任何调味品来打扮邪恶的全局状态,它仍然是全局状态。问题在于沙拉,而不是调料,可以这么说。

一个很少探索的路径是一元代码,Haskell 风格(在 C++ 中是)。我自己从未尝试过,但从外观上看,这个选项应该很有趣。请参阅此处以获取 C++ 中 Monad 接口的示例实现。

于 2013-04-07T09:46:53.303 回答