Reputation: 543
I am programming with an Arduino and my program contains a lot of while loops. When Arduino receives a character it must do some calculations and break from a loop that it has been in when it received a character. I will give you a simpler example (presume i and j are set to 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;
}
}
You can see that in both cases I used the same piece of code in the if sentences. What I want it to be able to write something like this.
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;
}
}
To break for a loop with an external method.
It gives me an error "break statement not within loop or switch", which is expected since it doesn't know which loop to break from but I was just wondering if it is possible to make something along those lines.
Thanks in advance!
Upvotes: 2
Views: 406
Reputation: 755
This is a perfect example why you should not use "break", "continue" or multiple return statements within a method/procedure. You are not able to extract methods to reduce redundancies. My advice is to reformulate your code to work without break-statements.
I would try following approach:
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"
}
Now you are able to improve the the code:
Extract methods and apply the template pattern to the calculation code (as far as possible in Arduino) to reduce redundancy.
Example of extracted method:
void determineString()
{
if (Serial.available() > 0)
{
setStringOne = "string one"
setStringTwo = "string two"
setStringThree = "string three"
setStringFour = "string four"
}
}
Upvotes: 1
Reputation: 344
You can do similar tricks with return
, though it might look little less obvious for some old-school programmers.
Assuming Serial.avaiable()
returns unsigned integer, you don't want to check it before your calculations, and you do actually need the updated i,j
counters as the post-effects when you update your strings, I would do it this way:
// 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);
Note that in the end i,j
yield the same values as in your example.
Another funny way is:
// 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
You can also extract your calculations into functions:
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()); );
This way you get your < 256
check first, then calc1/calc2
are executed with the old i/j
values, afterwards the i/j
value gets incremented, and then the check is performed. If the check returns true, the whole for
loop terminates.
Beware that those practices are not aligned with the KISS principle, so may you adjust your code, pre-conditions and post-effects to simply write
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
Upvotes: 1
Reputation: 993
You can't break like that, so no way. Just balance out what each method does:
while (i < 256)
{
if (Serial.available() > 0)
{
setThoseStrings();
break;
}
i++;
}
Alternatively
while (i < 256)
{
if (checkSerialAndSetStrings())
{
break;
}
i++;
}
This looks shorter but if you ever need to set strings in other situations (e.g. setting them when a timer runs out), you'll just waste time removing the serial check from checkSerialAndSetStrings
and updating your code. I'd go with #1.
Upvotes: 6