【问题标题】:Break from a loop with an external method使用外部方法从循环中中断
【发布时间】:2016-07-02 14:09:23
【问题描述】:

我正在使用 Arduino 进行编程,我的程序包含很多 while 循环。当 Arduino 接收到一个字符时,它必须进行一些计算并打破它在接收到一个字符时所处的循环。我给你举个更简单的例子(假设 i 和 j 都设置为 0):

while (i < 256)
{
    // some calculations #1
    i++;

    if (Serial.available() > 0)
    {
        setStringOne = "string one"
        setStringTwo = "string two"
        setStringThree = "string three"
        setStringFour = "string four"

        break;
    }
}

while (j < 256)
{
    // some calculations #2
    j++;

    if (Serial.available() > 0)
    {
        setStringOne = "string one"
        setStringTwo = "string two"
        setStringThree = "string three"
        setStringFour = "string four"

        break;
    }
}

您可以看到,在这两种情况下,我在 if 语句中都使用了相同的代码。我希望它能够写出这样的东西。

while (i < 256)
{
    // some calculations #1
    i++;

    if (Serial.available() > 0)
        checkAndBreak();
}

while (j < 256)
{
    // some calculations #2
    j++;

    if (Serial.available() > 0)
        checkAndBreak();
}

void checkAndBreak()
{
    if (Serial.available() > 0)
    {
        setStringOne = "string one"
        setStringTwo = "string two"
        setStringThree = "string three"
        setStringFour = "string four"

        break;
    }
}

使用外部方法中断循环。

它给了我一个错误“break statement not within loop or switch”,这是意料之中的,因为它不知道要从哪个循环中断,但我只是想知道是否有可能按照这些思路进行操作。

提前致谢!

【问题讨论】:

  • 您可以使用checkAndBreak 宏或异常或longjmp
  • 将循环条件更改为 while (j &lt; 256 &amp;&amp; Serial.available() &lt;= 0 ) 应该可以让您摆脱中断
  • 哦,我还没想过。谢谢。
  • 你考虑过使用异常吗?
  • 我从未在 Arduino 上处理过异常,所以我真的不知道如何实现它们。

标签: c++ loops arduino


【解决方案1】:

你不能那样打破,所以没办法。只需平衡每种方法的作用即可:

while (i < 256)
{
      if (Serial.available() > 0)
      {
             setThoseStrings();
             break;
      }
      i++;
}

或者

while (i < 256)
{
        if (checkSerialAndSetStrings())
        {
               break;
        }
        i++;
}

这看起来更短,但是如果您需要在其他情况下设置字符串(例如,在计时器用完时设置它们),您只会浪费时间从 checkSerialAndSetStrings 中删除串行检查并更新您的代码。我会选择#1。

【讨论】:

  • 好吧,我想我得把它变成这样。无论如何感谢您的回答。 :)
【解决方案2】:

您可以使用return 做类似的技巧,但对于一些老派程序员来说可能看起来不太明显。 假设Serial.avaiable() 返回无符号整数,您不想在计算之前检查它,而您确实需要更新后的@987654323 @计数器作为更新字符串时的后效,我会这样做:

// Obviously this function somehow has
// access to the strings being modified
// And possibly to some other state affected by calculations #1 and #2
// I'm leaving it similar to how you've written it
// for the sake of clarity
bool checkAndBreak()
{
    if (!Serial.available())
        return false;

    setStringOne   = "string one";
    setStringTwo   = "string two";
    setStringThree = "string three";
    setStringFour  = "string four";

    return true;
}

size_t i = 0, j = 0;

do {
    // calculations #1
} while (++i, !checkAndBreak() && i < 256);

do {
    // calculations #2
} while (++j, !checkAndBreak() && j < 256);

请注意,最后i,j 产生的值与您的示例中的值相同。 另一个有趣的方法是:

// define `i,j` outside of the loops if you need their final values
// !i and !j checks are to make sure checkAndBreak() 
// won't execute before the loop body
for (size_t i = 0; (!i || !checkAndBreak()) && i < 256; ++i)
    // calculations #1
for (size_t j = 0; (!j || !checkAndBreak()) && j < 256; ++j)
    // calculations #2

您还可以将计算提取到函数中:

void calc1(size_t i) { ... }
void calc2(size_t j) { ... }

for (size_t i = 0; i < 256 && (calc1(i++), !checkAndBreak()); );
for (size_t j = 0; j < 256 && (calc2(j++), !checkAndBreak()); );

这样你首先得到你的&lt; 256 检查,然后calc1/calc2 使用旧的i/j 值执行,然后i/j 值增加,然后执行检查。如果检查返回 true,则整个 for 循环终止。

请注意,这些做法不符合 KISS 原则,所以您可以调整您的代码、前置条件和后效,以便简单地编写

for (size_t i = 0; i < 256; ++i)
{
    // do the calculations #1
    // now check the side effects of those calculations
    if (serialCheckedAndStateChanged())
        break;
}
// The same for #2

【讨论】:

  • 非常有用的例子。谢谢!
【解决方案3】:

这是一个完美的例子,为什么您不应该在方法/过程中使用“break”、“continue”或多个 return 语句。您无法提取方法来减少冗余。我的建议是重新编写您的代码以在没有中断语句的情况下工作。

我会尝试以下方法:

do {
    // some calculations #1
    i++;
} while (i < 256 && Serial.available() == 0)

if (Serial.available() > 0)
{
    setStringOne = "string one"
    setStringTwo = "string two"
    setStringThree = "string three"
    setStringFour = "string four"
}

do {
    // some calculations #2
    j++;

} while (j < 256 && Serial.available() == 0)

if (Serial.available() > 0)
{
    setStringOne = "string one"
    setStringTwo = "string two"
    setStringThree = "string three"
    setStringFour = "string four"
}

现在您可以改进代码了:

提取方法并将模板模式应用于计算代码(尽可能在Arduino中)以减少冗余。

提取方法示例:

void determineString()
{
    if (Serial.available() > 0)
    {
        setStringOne = "string one"
        setStringTwo = "string two"
        setStringThree = "string three"
        setStringFour = "string four"
    }
}

【讨论】:

  • 谢谢。是的,我还重写了我的代码以不使用中断,并且我摆脱了一些冗余。
  • 您假设Serial.available() 没有副作用并且是免费的,因此在每次循环后再次调用它。如果您确实想摆脱中断,那么正确的方法是将每个循环提取到一个函数中进行计算,并在迭代结束时返回 true Serial.available() &gt; 0false
  • 你是对的:“Serial.available()”“[...] 没有副作用并且免费 [...]”是一个猜测。我希望该方法可以命名。在我查了一下之后,我的假设似乎离现实并没有那么远。 (arduino.cc/en/Serial/Available)。
  • 假设“Serial.available()”很昂贵。然后我也不会使用表明正确执行或任何其他隐藏语义的布尔返回函数。我将介绍代表缓存的代码片段。
猜你喜欢
  • 1970-01-01
  • 2013-06-07
  • 2015-06-28
  • 2012-09-20
  • 2018-01-24
  • 1970-01-01
  • 2015-12-12
  • 2011-01-28
  • 2015-01-09
相关资源
最近更新 更多