在#define宏中创建实例

时间:2019-01-16 11:35:18

标签: c++ arduino

我不会这样: #define some_func(a) some_func(a, create_foo())

,然后在使用时:

 void loop() {
     some_func(3);
     some_func(40);
 }

Foo实例仅应为每行创建一次。 因此,在上述情况下,是2次。并且当循环再次运行时,它不应再次创建Foo实例。

这可能吗?

这是完整的不可用程序: 输出应为3, 40, 6, 80, 9, 120, 12, 160, ...

typedef struct {
  int a;
} Foo;

Foo create_foo() {
  return {0};
}

void some_func(int a, Foo &f) {
  f.a += a;
  Serial.println(f.a);
}

#define some_func(a) some_func(a, create_foo())


void setup() {
  Serial.begin(9600);
}

void loop() {
  some_func(3); // 3, 6, 9, 12
  some_func(40); // 40, 80, 120, 160
}

编辑。

我试图将示例隔离到最低限度,但现在我正在朝自己开枪。实际上,我没有void作为返回类型,而是boolean

所以我现在尝试这样的事情:

#define debounce(val) for(static auto d = create_debounce(); debounce(d, val), false;)

但是当与以下项一起使用时,那当然会失败: int state = debounce(digitalRead(BUTTON_FIRE));

因为宏没有提供值,所以无法进行赋值。

所以我需要类似的东西: #define debounce(val) true; for(static auto d = create_debounce(); debounce(d, val), false;)

其中truecreate_debounce函数的结果。

那么,可以进一步毒化使其成为可能吗?这是完整的代码:

// ----------------- L I B R A R Y .  S T U F F -------------------------

#define debounce_delay 50

typedef struct {
    int state;
    int last_state;
    unsigned long last_state_change_time;    
} Debounce;

Debounce create_debounce() {
    return {0, 0, 0L};
}

boolean debounce(Debounce &deb, int val) {

    if (val != deb.last_state) {
        deb.last_state_change_time = millis();
        deb.last_state = val;
    }
    else if ((millis() - deb.last_state_change_time) > debounce_delay) {
        deb.state = val;
    }
    return deb.state;
}



//#define debounce(val) for(static auto d = create_debounce(); debounce(d, val), false;)
#define debounce(val) true; for(static auto d = create_debounce(); debounce(d, val), false;)


// ----------------- S K E T C H -------------------------

#define BUTTON_FIRE 7


void setup() {
  Serial.begin(9600);
}


void loop() {

  int state = debounce(digitalRead(BUTTON_FIRE));

  if (state == HIGH) {
    Serial.println("HIGH");
  }
  else {
    Serial.println("LOW");
  }

}

4 个答案:

答案 0 :(得分:3)

如果您愿意真正做到 丑陋,您几乎可以完成任何事情。我只是回答这个问题,因为这是一个脑筋急转弯。

您可以这样定义宏:

#define some_func(a) for(static auto f = create_foo(); some_func(a, f), false;)

是的,这将起作用。在标准C ++中,for循环的init子句可以包含静态变量声明。因此,该变量将仅初始化一次。然后,“条件”是对some_func的实际调用,后面是逗号操作符与false的调用,因此,每次进入for循环时,该函数仅执行一次。

将您的代码从Arduino适配到标准C ++,并模拟四个周期,生成所需的相同输出。 See it live


或者,如果您想使隐秘性降低一些(但是为什么呢?),您可以选择以下方式:

#define some_func(a) do {static auto f = create_foo(); some_func(a, f); } while(0)

确实如此。


好的,将其应用于您的 actual 问题需要采取一些不同的措施:

#define debounce(a) [](int v){static Debounce d = create_debounce(); \
                              return debounce(d, v); }(a)

这定义并立即调用一个lambda。由于lambda会在程序中出现的所有位置创建唯一的闭包类型,因此这会为您在其中写入debounce(...)的每个表达式创建唯一的静态对象。另一种方法是GCC特定的语句表达式。但是与lambda不同,它是扩展。您可能会或不想使用的YMMV。

答案 1 :(得分:1)

再次运行循环时,将再次创建Foo实例,它们不会从上一次运行中恢复。

我怀疑您要使用一组静态变量。或为了清晰起见,重构代码。

此宏在此问题上无济于事,不使用它,使用显式变量,然后您将看到对象的生存期。宏不是编译器的一部分,而是预处理器的一部分。

答案 2 :(得分:0)

除了格式不正确之外,您的宏还无法满足您的需求,因为您每次调用时都在调用create_foo

您可以使用静态变量:

void loop() {
    static Foo f1, f2;
    some_func(3, f1);
    some_func(40, f2);
}

答案 3 :(得分:0)

首先要注意的是,您的状态为布尔值。这将为您节省一些字节的RAM。

接下来要指出的是,您要在一段时间内忽略对输入的更改;这意味着您不需要存储“当前”状态;只是最后一个状态...最终将保持不变。这可能不会为您节省任何费用,因为2个布尔值和1个布尔值可能只占用一个字节;但它为编译器提供了机会,最重要的是,它使事情变得更简单。

在进行了2项相当小的改进后,我们获得了更大的改进。除非您真的知道自己在做什么,否则不要使用宏。甚至重新考虑。

Arduino示例代码倾向于提供它们,因为有人认为这样做会使学习变得更容易。但老实说,他们没有。它们不是功能,您对它的使用实际上并没有达到您认为正在做的事情。 Arduino提供了有限的调试方法,因此您实际上无法说出状态永远会很高,因为宏扩展是这样的:

int state = true; 
for(static auto d = create_debounce(); 
    debounce(d, val), 
    false;);
//New lines added for clarity.

将其移至功能;让编译器优化代码,因为只要您以允许的方式编写代码,它就会总是比您做得更好。