Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

top level `continue` in nested loop C instead of current level loop

Tags:

c

nested-loops

How do I make continue goes to the top level of loop? I mean like this:

for(;;){ // top level loop
   statement1;
   for(;;){ // second level loop
      statement2;
      if (condition1){
         continue; // I expect it continue to the start of top level so it will execute statement1.
      }
   }
   statement3;
}

This is my real case why I got problem above, basically my program is sending data with UDP socket which the data should be sent fast. I know UDP is unrealiable but it's okay the data is tolerated with loss too.

 for (;;) {  // Streaming data...
    camera_fb_t* fb = esp_camera_fb_get();
    size_t quotient = fb ->len / UDP_BUF_SIZE;
    size_t remainder = fb ->len % UDP_BUF_SIZE;
    unsigned int i = 0;
    for (; i < quotient; i++) {  // sending packet by packet.
      if (uwc_udp_send_raw((const void*)(fb ->buf + (i * UDP_BUF_SIZE)),
                           UDP_BUF_SIZE) < 0) {
        ESP_LOGE(uwc_tag_event, "Error in iteration: %i", i);
        uwc_udp_send_raw("ERR",3); // Tell receiver there was corrupt during send data.
        esp_camera_fb_return(fb);
        continue; // I expect it continue to the top level
      }
    }
    if (remainder) {  // last packet to be sent if remainder exist
      uwc_udp_send_raw((const void*)(fb ->buf + (i * UDP_BUF_SIZE)),
                       remainder);
      ESP_LOGE(uwc_tag_event, "Error in last iteration!");
    }
    esp_camera_fb_return(fb);
  }
like image 877
Citra Dewi Avatar asked Apr 27 '26 16:04

Citra Dewi


1 Answers

This is a rare case where you may use a goto. * Ducks for cover expecting flame-war and down votes *

People will get excited and declare your code automatically unreadable by a single use of goto and generally wring their hands. But in these very rare cases the cleanest and most readable code has a goto. There are exceptions to almost every rule!

Remember, there is almost always a better way than using goto but the real issue with it is that liberal use quickly creates 'spaghetti' code. But a single use can be justified.

#include <stdio.h>

int foo(){
    for(int i=0;i<10;++i){
        for(int j=0;j<10;++j){
            if(j==i*i){
                goto OUTER_LOOP;
            }
        }
        printf("%d\n",i);
OUTER_LOOP: continue;
    }
}

int main(void) {
    foo();
    return 0;
}

People will claim you should set a boolean and break and insist that is 'more readable'. It's no more readable at all. There are few dogmatic laws in programming but "goto is always an necessarily bad" is one of them. It's almost true. But not quite entirely true.

Java has a labelled break statement almost specifically to provide a way of avoiding this use-case for goto and doesn't have goto itself because it has a fix.

I think it's arguable that there is a tiny gap in the language. But in practice this situation is actually quite rare.

like image 133
Persixty Avatar answered Apr 29 '26 05:04

Persixty