c++ - 在嵌入式编程中避免使用全局变量

标签 c++ embedded global-variables

在我所涉足的嵌入式编程类型中,运行代码的确定性和透明性受到高度重视。我所说的透明度是指,例如,能够查看内存的任意部分并知道那里存储了哪些变量。因此,正如我确信嵌入式程序员所期望的那样,尽可能避免使用 new,如果无法避免,则仅限于初始化。

我理解这样做的必要性,但不同意我的同事这样做的方式,我也不知道更好的选择。

我们有几个全局结构数组和一些全局类。有一组用于互斥锁的结构,一组用于信号量,还有一组用于消息队列(这些在 main 中初始化)。对于运行的每个线程,拥有它的类是一个全局变量。

我遇到的最大问题是单元测试。当我想测试 #include 的全局变量但我不想测试该类时,如何插入模拟对象?

这是伪代码中的情况:

foo.h

#include "Task.h"
class Foo : Task {
public:
  Foo(int n);
  ~Foo();
  doStuff();
private:
  // copy and assignment operators here
}

bar.h

#include <pthread.h>
#include "Task.h"

enum threadIndex { THREAD1 THREAD2 NUM_THREADS };
struct tThreadConfig {
  char      *name,
  Task      *taskptr,
  pthread_t  threadId,
  ...
};
void startTasks();

bar.cpp

#include "Foo.h"

Foo foo1(42);
Foo foo2(1337);
Task task(7331);

tThreadConfig threadConfig[NUM_THREADS] = {
  { "Foo 1", &foo1, 0, ... },
  { "Foo 2", &foo2, 0, ... },
  { "Task",  &task, 0, ... }
};

void FSW_taskStart() {
    for (int i = 0; i < NUMBER_OF_TASKS; i++) {
        threadConfig[i].taskptr->createThread(  );
    }
}

如果我想要更多或更少的任务怎么办? foo1 的构造函数中有一组不同的参数?我想我必须有一个单独的 bar.h 和 bar.cpp,这似乎比必要的工作要多得多。

最佳答案

如果您想先对此类代码进行单元测试,我建议您阅读 Working Effectively With Legacy Code另见 this .

基本上使用链接器插入模拟/假对象和函数应该是最后的手段,但仍然完全有效。

然而,您也可以使用控制反转,如果没有框架,这会将一些责任推给客户端代码。但它确实有助于测试。例如测试 FSW_taskStart()

tThreadConfig threadConfig[NUM_THREADS] = {
  { "Foo 1", %foo1, 0, ... },
  { "Foo 2", %foo2, 0, ... },
  { "Task",  %task, 0, ... }
};

void FSW_taskStart(tThreadConfig configs[], size_t len) {
    for (int i = 0; i < len; i++) {
        configs[i].taskptr->createThread(  );
    }
}

void FSW_taskStart() {
    FSW_taskStart(tThreadConfig, NUM_THREADS);
}

void testFSW_taskStart() {
    MockTask foo1, foo2, foo3;
    tThreadConfig mocks[3] = {
          { "Foo 1", &foo1, 0, ... },
          { "Foo 2", &foo2, 0, ... },
          { "Task",  &foo3, 0, ... }
        };
    FSW_taskStart(mocks, 3);
    assert(foo1.started);
    assert(foo2.started);
    assert(foo3.started);
}

现在您可以将线程的模拟版本传递给“FSW_taskStart”,以确保该函数确实按要求启动线程。不幸的是,您必须依赖原始 FSW_taskStart 传递正确参数的事实,但您现在正在测试更多代码。

关于c++ - 在嵌入式编程中避免使用全局变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1274484/

相关文章:

c++ - 使用 malloc 初始化一个类

javascript - Meteor 和 MongoDB 地理空间 - 边界 - $within

c++ - 创建一个类,类名作为模板参数给出

c++ - 如何将对象从 Delphi 7 传递到 C++ dll?

c++ - 即使指针在函数堆栈中,我是否也必须删除它?

javascript - 为什么函数声明会覆盖全局对象的不可写属性?

python - 在 python 中使用命令行参数标志的正确方法

c++ - 如何使用 QT 命名空间中使用的重载 new 运算符

c - 如何防止系统在看门狗定时器任务启动前挂起

memory-leaks - 如何从 lwIP 的 mem_malloc 获取可用内存?