In “Spilling the Beans: Endless Loops” several ways of creating and using endless loops were discussed. In this ‘bean’ it is about how to exit or break a loop.

Usually a loop has a ‘ending condition’. The following examples print 5 messages each:
for(int i=0; i<5; i++) {
printf("i: %d\n", i);
}
int i = 0;
do {
printf("i: %d\n", i);
i++;
} while(i<5);
int i = 0;
while (i<5) {
printf("i: %d\n", i);
i++;
}
The result will be something like this:
i: 0 i: 1 i: 2 i: 3 i: 4
π‘ I’m using printf() for illustration purposes. I’m not a fan of using printf() in an embedded environment, see “Why I donβt like printf()” π
But what if a condition happens to leave the loop earlier, just in case?
There is the break keyword in C/C++ which allows you to get out of a loop earlier. A break causes the execution to ‘break out’ the surrounding ‘for’, ‘while’ or ‘do-while’ loop.
For example
for(int i=0; i<5; i++) { /* breaks! */
if (i==3) {
break; /* leave loop! */
}
printf("i: %d\n", i);
}
will only print
i: 0 i: 1 i: 2
π‘ The break keyword can be used inside a ‘switch‘ expression too, but it has different role there which is not covered here.
Keep in mind that the break affects the surrounding loop. So if you have nested loops and do a break, it will only break out one level.
The following example shows this:
for(int i=10; i<13; i++) {
printf("i: %d\n", i);
for (int j=0; j<10; j++) { /* breaks! */
if (j==2) {
break; /* leave for loop with j */
}
printf("j: %d\n", j);
}
}
Will produce something like this:
i: 10 j: 0 j: 1 i: 11 j: 0 j: 1 i: 12 j: 0 j: 1
‘Breaks’ in loops should be used carefully: they can make the code hard to read and ‘interrupt’ the normal flow. For sure you have noticed in above snippets my /* breaks! */ comment to warn the reader about this.
There is one use case were I use ‘break’ in endless loops: in a kind of ‘exception’ handling. Consider the following (simplified) example, where it is about to send a message:
ErrorCode_e Send(const unsigned char *msg) {
ErrorCode_e ret;
Communication_t comm;
uint32_t crc;
if (OpenCommunication(comm)) {
if (CalcCrc(msg, &crc)) {
if (SendMessage(comm, msg, crc)) {
ret = ERR_CODE_OK;
} else {
ret = ERR_CODE_COM_SEND_FAILED;
}
CloseCommunication(comm);
} else {
ret = ERR_CODE_COM_CRC_FAILED;
CloseCommunication(comm);
}
} else {
ret = ERR_CODE_COM_OPEN_FAILED;
}
return ret; /* return error code */
}
The code is a sequence of steps (open communication, calculating a CRC and sending the message), each step with some error handling, each guarded with some ‘if’. The challenge is that the if-nesting can get rather high and affect readability.
Another way is to pack the ‘sequence’ of operations into an endless loops which breaks in case of error, with a ‘finally’ section at the outside of the loop. The above code then looks like this:
ErrorCode_e Send(const unsigned char *msg) {
ErrorCode_e ret = ERR_CODE_OK;
Communication_t comm = NULL;
uint32_t crc;
do { /* breaks! */
if (!OpenCommunication(&comm)) {
ret = ERR_CODE_COM_OPEN_FAILED;
break; /* error case */
}
if (!CalcCrc(msg, &crc)) {
ret = ERR_CODE_COM_CRC_FAILED;
break; /* error case */
}
if (!SendMessage(comm, msg, crc)) {
ret = ERR_CODE_COM_SEND_FAILED;
break; /* error case */
}
} while(false);
CloseCommunication(comm); /* 'finally' */
return ret; /* return error code */
}
Personally I feel such a ‘string of actions’ easier to read, plus the ‘finally’ part ensures that necessary cleanup gets done (if any). For sure this is not up to the level of a ‘try-catch’ in an OOP programming language, but does the job efficiently.
If you have different ways and thoughts, post a comment π
Happy breaking π
Maybe it is just my browser, in what should be the ‘outputs’ of “the result will be something like this:”
There is only the line number counts on the left. No actual text, for the first two examples. Just counts of 1,2,3,4 and 1,2.
LikeLiked by 1 person
Hi Bob,
yes, that’s correct. Because it only prints the number plus a newline, nothing else. But I see your point: maybe it should print the variable name too, will update it.
LikeLike
I really must have been a browser issue because it looks different over here.
Now I see :
i:0
i:1
i:2
i:3
i:4
i:0
i:1
i:2
Before only the numbers were there and I thought they were meant to be line numbers of commented code.
LikeLiked by 1 person
Yes, makes more sense with the ‘i:’ in there.
LikeLiked by 1 person
Iβm a big fan of the βstring of error conditions inside a do { β¦ } while false;β construct. Glad to see it mentioned as a good use for break statements!
Question for you (and perhaps a topic for a future bean blog): when do you βdo everything in the header of a for loopβ vs adding things to the body? Consider this contrived example of strncpy(written off the top of my head and likely to be buggyβ¦):
char *my_strncpy(char *dst, const char *src, size_t n) {
char *d;
size_t i;
for (i=0, d=dst; i<n; i++, *d++ = (*src == '\0') ? '\0' : *src++) {
// I ain't got no body
}
return dst;
}
LikeLiked by 1 person
Hi Robert,
good topic suggestions, I call this the ‘scope of variables’. There are pros and cons to have it either in the header or inside the {}. I plan to get on that subject, so thanks again.
LikeLike
When you wrote ‘OpenCommunication(comm)’, did you really mean ‘OpenCommunication(&comm)’, so a handle can be returned?
Best Regards, Dave
LikeLiked by 1 person
Hi Dave,
yes, good catch! Fixed now.
LikeLike
This also lends itself well to using {…} to further create new scopes within the do-while for local initializations. However, I think this is also one of those cases where a goto is perfectly justified. (and now come the heresy claims)
LikeLike
Yes, a goto could be used here too. As with every tool, goto can be used well. But only carefully, if it cannot be avoided for some good reasons. Here it can be avoided :-). The other thing is that for example MISRA or other coding guidelines do not allow it (except with some good justifications).
LikeLike
I think MISRA lets you get away with anything as long as you “justify” it… I notice it a lot in the FreeRTOS kernel. π
Luckily, I don’t have to code to MISRA and frankly I dont want to, I hate having my hands tied just because a certain practice or pattern ‘might’ introduce an unintended side effect.
But this sounds like ANOTHER TOPIC and I would love to know other peoples
thoughts on MISRA who have actually used it in the real world and had to abide by it.
LikeLiked by 1 person
Yes, MISRA or any coding guideline for sure is another possible topic I plan to cover.
LikeLike
Totally agree with the use of goto in the last case exemplified here. Break is basically nothing more than just a “handicapped” goto in disguise. Just consider the extra “gymnastics” (i.e. the addition of a dummy do{}while(false) ) required just to make it work. Add to that the fact that the reader must also decipher the scope of nearest loop to find the line to be executed next.
Goto just serves all that in plain text (augmented also by a properly named label).
In this case, I believe the focus should be on readability, not avoiding the use of goto. That’s what I would preach about…
Otherwise, I love this blog. Keep up the good work!
– AP
LikeLiked by 1 person
Yes, I call the switch expression a ‘structured goto’. As for everything, even for ‘bad’ things there are some places where it can be used in good ways. So I’m not banning ‘goto’, but as for everything like this: it needs to be used in a justified and reasonable way.
LikeLike
Pingback: Spilling the Beans: storage class and linkage in C, including static locals | MCU on Eclipse