"全球"和"单身"的"事物"的全局变量?

Fre*_*pin 2 c++ embedded microcontroller design-patterns

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

如果我希望我的程序很好地面向对象,我很难决定如何处理这些对象...全局变量并不好,这很明显,但我只是不知道(不够经验)我是否应该试图"隐藏"这些东西是全局的事实......例如"cin"或"stdout"也是全局的(让我们忽略这样一个事实:在多线程应用程序中这些通常是特定于线程的)并且没有人隐藏着......让我们坚持使用时钟发生器外设 - 只有一个,所以我可以使用单例反模式(;或者让类静态或者让单个对象全局化(这就是我通常所做的) ,因为这个对象存储了当前时钟设置,所以很多其他东西都需要这个值 - 需要设置RTOS使用的系统定时器,需要为其他外设设置时钟(UART波特率,SPI比特率......) ,需要为外部存储器设置正确的时钟或配置存储器等待状态.这就是我认为的原因 在main()中创建一个对象并将其传递到任何地方会有点麻烦......

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

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

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

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

Ulr*_*rdt 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();
}
Run Code Online (Sandbox Code Playgroud)

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

有两个指导方针可以使这更容易:

  • 对象的范围越大,它需要的说话名称就越多(与上面的a,b,c相比).在您的情况下,我将所有特定于硬件的对象存储在一个公共命名空间中,因此很明显有些代码正在访问全局变量.这也允许单独测试和重用此命名空间.许多硬件供应商甚至以库的形式提供这样的东西,以帮助应用程序开发.
  • 在代码包装/建模硬件中,执行请求但不做出基于应用程序的特定于应用程序的决策.与标准流相比,标准流提供但从未被标准库本身使用,除非在断言失败后中止之前转储致命错误信息.