Spilling the Beans: Breaking Loops

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.

Photo by monicore on Pexels.com

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 πŸ™‚

15 thoughts on “Spilling the Beans: Breaking Loops

  1. 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.

    Liked by 1 person

      • 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.

        Liked by 1 person

  2. 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;
    }

    Liked 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.

      Like

  3. 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)

    Like

    • 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).

      Like

      • 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.

        Liked by 1 person

    • 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

      Liked 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.

        Like

  4. Pingback: Spilling the Beans: storage class and linkage in C, including static locals | MCU on Eclipse

What do you think?

This site uses Akismet to reduce spam. Learn how your comment data is processed.