我不会这样:
#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;)
其中true
是create_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");
}
}
答案 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.
将其移至功能;让编译器优化代码,因为只要您以允许的方式编写代码,它就会总是比您做得更好。