Help with use of goto

Please can someone help with this. I have written a simple sketch to try to understand why I cannot get goto to work in a main program I am working on. (I am inexperienced at C++ , and although I know goto is not advised, I think it would be simpler for my application.
However I cant get the simple sketch (attached) to work either. It will not compile with error "label1 Label2 used but not defined". Goto is listed in the Arduino reference & I cannot see what is wrong.


int a = 0;
void setup() {
  Serial.begin(9600);
  int a = 0;
}
void print() {
  label2; {
    Serial.println("label2 has sent me back to label1");
  }
label1: {
    Serial.println("am at label1");
  }
  for (int a = 0; a < 100; a++)
  {
    Serial.println(a);
    delay(100);
  }
  if ( a >= 50)
  { Serial.println("going to label2");
    goto label2;
  }

}

void loop() {
  // put your main code here, to run repeatedly:
  //label2: Serial.println("am at label2");
  delay(5000);
  goto label1;
}

I
I've not used goto, but these look odd:

In one place you have
label2;

In one place you have
label1:

You jump from loop() into the middle of print().

In C++ we use functions instead of goto. The use of goto leads to spaghetti code which is very difficult to read, follow and debug.

If you tell us, in detail, what you want to do we can probably help you to write functions to do it.

1 Like
int a = 0;
}

What's the point of a variable that immediately goes out of scope?

I got it to compile by making label1() and label2() into functions that can be called, and got rid of the print() function.

int a = 0;
void setup() {
  Serial.begin(9600);
  int a = 0;
}

void label2() {
  Serial.println("label2 has sent me back to label1");
  label1();
}
void label1() {
  Serial.println("am at label1");

  for (int a = 0; a < 100; a++)
  {
    Serial.println(a);
    delay(100);
  }
  if ( a >= 50)
  { Serial.println("going to label2");
    label2();
  }
}

void loop() {
  // put your main code here, to run repeatedly:
  //label2: Serial.println("am at label2");
  delay(5000);
  label1();
}
1 Like

In addition to the typo @CrossRoads pointed out, you can not jump (e.g. GOTO) into the middle of another function. Labels inside your Print() function are only visible to code inside that function.

There are many, many better alternatives to GOTO. What are you actually trying to do?

Lots of problems here with the first being you can't use goto to jump into a function. But really, you should study the use of the while and do while control structures and not use goto. I assure you that your code will easier to follow without gotos.

Another problem in your code is variable scope. The for loop declares a variable "a" which is local to that loop and is not the same that is referenced in the if statement, which is a global variable. The global variable will always be zero, so the a>=50 expression will always be false.

Don't !! label1() calls label2() which calls label1() so we have recursion and you code will run out of memory.

What saves you in this case is that variable a will never be greater or equal than 50.

  if ( a >= 50)
  { Serial.println("going to label2");
    label2();
  }

Just needs a } moved

49
50
going to label2
label2 has sent me back to label1
I am at label1
0
1
2
int a = 0; // <<<< makes a into a global variable
void setup() {
  Serial.begin(9600);
  int a = 0; // <<<< int not needed here
}

void label2() {
  Serial.println("label2 has sent me back to label1");
  label1();
}
void label1() {
  Serial.println("I am at label1");

  for (int a = 0; a < 100; a++) // <<< int not needed here
  {
    Serial.println(a);
    delay(100);

    if ( a >= 50)
    { Serial.println("going to label2");
      label2();
    }
  }
}

void loop() {
  // put your main code here, to run repeatedly:
  //label2: Serial.println("am at label2");
  delay(5000);
  label1();
}

That code is recursive and will eventually overrun the memory.

Yup, it does. I reduced the delay(100) to just 10, and it takes 36 or 37 iterations to crash, and loop to restart.

This doesn't crash tho

int a = 0;
void setup() {
  Serial.begin(9600);
  a = 0;
}

void label2() {
  Serial.println("this is label2");
  ;
}
void label1() {
  Serial.println("this is label1");

  for (a = 0; a < 100; a++)
  {
    Serial.println(a);
    delay(10);

    if ( a >= 50)
    { Serial.println("a is >= 50");
      break;
    }
  }
}

void loop() {
  // put your main code here, to run repeatedly:
  Serial.println("Starting loop()");
  delay(3000);
  label1();
  label2();
}
Starting loop()
this is label1
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
a is >= 50
this is label2
Starting loop()
this is label1
0
1

Seems the TO has changed back to same basic-dialect to use goto without beeing disturbed by functional programming users.

after the professor told us he'd fail us for using goto, i finally figured out their valid use in unix and other examples

in your code , there's no need for a goto, this isn't assembly code. (on my first embedded project, my supervisor said there's a bunch of assembly programmers writing assember programs in C).

look at section 3.5 Loops - While and For on pg 56 in The C Programming Language

the conventional approach is when some cleanup or post processing is needed (not illustrated)

    do {
        // something
    } while (a >= 50);

but where i've used goto in such a situation is

void func () {
    do {
        for (int a = 0; a < 100; a++)
        {
            if (someErrorCondition)
                goto err;
        }
    } while (a >= 50);

    // normal exit
    return;

err:
    // error exit
    printf ("%s: something bad happened\n", __func__);
    return;
}

Thanks for the answers but the code was just for me to try to get to understand what the compiler needs to accept the goto labels definition. It complains that they are not defined.

Because of scope - you can't goto into another function, mostly for the reasons already discussed.

There were some basic errors, some redundant code, and one 'goto' trying to jump to a label that was not in scope. I fixed what I could and worked around the invalid code. It's been running for 567 iterations without crashing.

The output (using shorter loop to reduce waiting):

4
5
going to label2
label2 has sent me back to label1
Am at label1.  565
0
1
2
3
4
5
going to label2
label2 has sent me back to label1
Am at label1.  566
0
1
2
3
4
5
going to label2
label2 has sent me back to label1
Am at label1.  567
0
1
2
3

The corrected code:

int Iterations = 0;

void setup()
{
  Serial.begin(115200);
  delay(200);
  Serial.println("In setup().");
}

void print()
{
  goto label1;
  
label2:
  Serial.println("label2 has sent me back to label1");

label1:
  Serial.print("Am at label1.  ");
  Serial.println(Iterations++);

  for (int a = 0; a < 10; a++)
  {
    Serial.println(a);
    delay(100);

    if ( a >= 5)
    {
      Serial.println("going to label2");
      goto label2;
    }
  }
}

void loop()
{
  // goto label1;  // Can't go to a label outside the current function
  // Instead: call the function:
  print();
}

In the OP's code, label2 is followed by a semicolon and I'm pretty sure labels are followed by a colon.

Edit: Also, if you're crossing scope levels, do you have to use setjmp() and longjmp()? (It's been a long time since I've used either.)

Hello
Take a view here for the requested definition.
https://www.arduino.cc/reference/en/language/structure/control-structure/goto/

if this is just for knowing it. Fine. As previously said:
using goto in code leads to what's called "spaghetti"-code.

Program-execution jumps up and down in a way that will it make very hard to understand your code after 4 weeks. You can ask any software-developer beeing a hobbyist or a professional they all avoid goto completely.

My point of view: yiu should learn functional programming.
Every function does one thing.

not sure what you wanted with your conditions seems akward to me.

anyway what would be so hard about coding that if an errorCondition occurs the do-while-loop will be exited;

void func () {
    do {
        for (int a = 0; a < 100; a++)
        {
        }
    } while (a >= 50 && !someErrorCondition );

    if (someErrorCondition) {
      printf ("%s: something bad happened\n", __func__);
    }  
    return;

best regards Stefan