【问题标题】:Switch case statement in function doesn't switch C++函数中的 switch case 语句不会切换 C++
【发布时间】:2019-12-24 00:27:20
【问题描述】:

我试图在两个不同的函数中使用两个 switch case 语句通过串行包控制微控制器,但是其中一个函数没有切换,程序无限循环。其中一项功能根据enum进行切换:

enum class State {

 example_a,
 example_b,
 example_c

};

void serialTask(State stateArg, ObjectA exampleA, ObjectB exampleB, ObjectC exampleC, ObjectD exampleD) {
  switch (stateArg) {
    case State::example_a:
      Serial.println("Serial Task, example a");
      exampleA.doSomething();
      stateArg = State::example_a;
      break;

    case State::example_b:
      Serial.println("Serial Task, example b");
      exampleB.doSomething();
      stateArg = State::example_b;
      break;

    case State::example_c:
      Serial.println("Serial Task, example c");
      exampleC.doSomething();
      stateArg = State::example_c;
      break;
   }
};

我将所有其他对象作为参数提供给它,因为根据情况我会调用它们的函数或修改它们的成员。

另一个函数根据串口切换enum的值:

void stateSwitch(State stateArg) {
    if (Serial.available()) {
        uint8_t code = Serial.read();
        switch (code) {
        case 'a':
            stateArg = State::example_a;
            break;
        case 'b':
            stateArg = State::example_b;
            break;
        case 'c':
            stateArg = State::example_c;
            break;
   }
};

他们后来在我的main.cpp 中被调用,如下所示:

ObjectA aObj;
ObjectB bObj;
ObjectC cObj;
ObjectD dObj;
volatile State stateObj;

void setup(){

stateObj = State::example_a;
Serial.begin(115200);


};

void loop(){

stateSwitch(stateObj);
serialTask(stateObj, aObj, bObj, cObj, dObj);

};

这是问题的简化版本,但它说明了重点。程序可以编译,但由于某种原因它不能跳出State::example_a。我在 PlatformIO 中使用带有 Arduino 框架的 Teensy 微控制器,这是 Visual Studio 的扩展。感谢您的帮助。

【问题讨论】:

  • 其他参数是按值传递的(即作为调用者传递的副本),因此调用者看不到对它们的任何更改。将参数更改为引用或指针

标签: c++ arduino switch-statement


【解决方案1】:

您通过值将stateArg 传递给stateSwitch

这意味着正在制作副本,并且您正在修改副本;不是原版。

【讨论】:

  • 非常感谢您的快速回复。我对 C++ 中的一些概念非常陌生。我应该创建一个复制构造函数吗?或者您如何将 stateArg 作为原始值而不是值传递?
  • 您应该做的是阅读您的 C++ 书籍并花一些时间阅读它,了解值传递的含义、引用传递的含义、它们的工作原理以及如何使用它们。这与任何人的复制构造函数无关。您在这里缺少一些基本的 C++ 基础知识。没关系,每个人都必须在某个时候学习它们,但不幸的是,stackoverflow.com 并不能替代一本好的 C++ 书籍。附言这里的volatile 关键字似乎也没有任何用处。同样,看起来您需要了解volatile 的含义以及何时应该使用它。请参阅您的 C++ 书籍。
  • @SamVarshavchik 感谢您的建议。我正在重新阅读指针和引用的基础知识,我认为现在我有一个需要使用它们的真实案例更清楚了。您对 volatile 关键字的看法是正确的,在示例中它没有意义,但在我的代码中却如此,因为我正在处理计时器和中断。
【解决方案2】:
void serialTask(State stateArg, ...
    stateArg = State::example_a; // affects local copy only

这是按值传递的,因此为函数制作了一个副本。它不会将任何更改回显到原始变量。

为此,您需要通过引用传递它:

void serialTask(State &stateArg, ...
    stateArg = State::example_a; // affects variable used in call

请注意,您需要在所有想要更改变量的函数中通过引用传递(所以stateSwitch 以及serialTask)。

例如,请注意以下几点:

#include <iostream>
void procA(int num) {
    num = 7;
}
void procB(int &num) {
    num = 42;
}
int main() {
    int num = 1; std::cout << num << '\n';
    procA(num);  std::cout << num << '\n';
    procB(num);  std::cout << num << '\n';
}

这将导致1142这三行,因为对procA的调用是按值传递的,它不会影响传递的变量,只是它的本地副本.

另一方面,procB 作为引用传递,确实更改了传递的变量。

另请注意,无论您是按值传递还是按引用传递,调用都是相似的。您无需以任何方式更改调用。


可能还想检查这些事情背后的逻辑:

case State::example_a:  // current state
      Serial.println("Serial Task, example a");
      exampleA.doSomething();
      stateArg = State::example_a; // why set to same/original state?
      break;

状态机强制将状态恢复到执行事件之前的值是非常不寻常的。 可能没关系,因为我们看不到您的所有代码,但我会小心的。

【讨论】:

  • 非常感谢您的帮助。我将stateSwitch的声明改为void stateSwitch(State &amp;stateArg);,并称之为stateSwitch(&amp;stateObj);。编译器首先告诉我它不能使用这样的 volatile 类型失败,所以我删除了它(我的对象现在只有State stateObj 而不是volatile State stateObj;)。现在它向我抛出了这个错误:invalid initialization of non-const reference of type 'State&amp;' from an rvalue of type 'State*'。我有点迷路了。
  • 再次感谢您的澄清。我仍然无法理解的是关于非常量引用的最后一个错误。这是否意味着编译器需要 const 数据类型?那没有意义,因为那样就不可能切换,对吧?关于上一部分的逻辑,我认为是重新创建示例时的错误,它不是我正在使用的真实代码的一部分,我一定忽略了它,只是在重新创建示例时继续。
  • @Antonio,你不应该改变调用本身,只改变声明。我会更新答案。基本上,通过传递&amp;State 而不是State,你传递了一个指向它的指针。因此,虽然它期望引用 State 类型的变量,但您给它的是 State* 变量。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-08-15
  • 2013-09-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多