name lookup of 'i' changed for new ISO 'for' scoping

I've written a simple brushless motor testing program, but i'm getting a weird error I've never seen before :fearful:!

What does this error mean and how do I fix it? Thanks in advance!
BTW the error happens somewhere in the for loop where 'i' is between 1500 and 1000 I think. The code works fine up till that point.

#include <LiquidCrystal.h>
#include <Servo.h> //Notice how you can use the standard servo library!

Servo bldc_motor; //creates a "servo" object (the ESC and motor)
LiquidCrystal LCD (2, 3, 4, 5, 6, 7); ///create an LCD


void setup()
{
  bldc_motor.attach (9); //attach the motor to pin 9
  LCD.begin (16, 2); //initialise the LCD
  LCD.clear(); 
}

void loop()
{
  bldc_motor.writeMicroseconds(1500); //provides a "neutral" pulse. The ESC won't start without this.
  LCD.print ("BLDC Motor Test");
  LCD.setCursor (0, 1);
  LCD.print ("Starting in ");
  
  for (int i = 4; i >= 0; i --) //countdown timer
  {
    LCD.setCursor (12, 1);
    LCD.print (i+1);
    LCD.print ("s");
    delay (1000);
  }
  
  LCD.setCursor (0, 1);
  LCD.print ("                "); //clears the bottom line of the LCD
  
  LCD.setCursor (5, 1);
  LCD.print ("forward"); //writing it here so it doesn't keep rewriting this in the for loop
  
  while(1)
  {
    for (int i = 1500; i <= 2000; i++)
    {
      int speed_value = map (i, 1500, 2000, 0, 100); //maps the signal pulse to a percentage
      LCD.setCursor (0, 1);
      LCD.print ("   "); //clears any previous number;
      LCD.setCursor (0, 1);
      LCD.print (speed_value); //prints the percentage to the LCD
      LCD.print ('%'); //notice the single quotation marks. I've just sent a char value, not a string because it's only 1 character
      
      bldc_motor.writeMicroseconds (i); //actually write the value to the motor
      delay(10);// small delay so you can see what's happening
    }
    
    LCD.setCursor (0, 1);
    LCD.print ("                "); // clears the bottom of the LCD screen;
    LCD.setCursor (0, 1);
    LCD.print ("braking in");
    
    for (int i = 4; i >= 0; i --) //countdown timer
    {
      LCD.setCursor (12, 1);
      LCD.print (i+1);
      LCD.print ("s");
      delay (1000);
    }
    
    bldc_motor.writeMicroseconds (1000); //full reverse. The ESC will automatically brake the motor.
    delay (500); //small delay to let things happen
    bldc_motor.writeMicroseconds (1500); //give a neutral signal
    LCD.setCursor (0, 1);
    LCD.print ("motor stopped");
    delay (3000); //keep it that way for a while
    
    LCD.setCursor (0, 1);
    LCD.print ("                "); //clear the bottom line of the LCD
    LCD.setCursor (5, 1);
    LCD.print ("backward");
    
    for (int i = 1500; i >= 1000; i --);
    {
      int speed_value = map (i, 1500, 1000, 0, 100); //maps the signal pulse to a percentage
      LCD.setCursor (0, 1);
      LCD.print ("   "); //clears any previous number;
      LCD.setCursor (0, 1);
      LCD.print (speed_value); //prints the percentage to the LCD
      LCD.print ('%'); //notice the single quotation marks. I've just sent a char value, not a string because it's only 1 character
      
      bldc_motor.writeMicroseconds (i); //actually write the value to the motor
      delay(10);// small delay so you can see what's happening
    }
    
    LCD.setCursor (0, 1);
    LCD.print ("                "); //clear bottom line of LCD
    
    bldc_motor.writeMicroseconds (1500);
    LCD.setCursor (0, 1);
    LCD.print ("motor stopped");
    delay (3000);    
  }
      
    
  
}

Error messages:

name lookup of 'i' changed for new ISO 'for' scoping

sketch_nov03a.cpp: error: In funcion 'void loop()':
sketch_nov03a:77: error: name lookup of 'i' changed for new ISO 'for' scoping
sketch_nov03a:37: error: using obsolete binding at 'i' (what on earth does this mean too?)

Add a declaration for "i" after loop, eg.

void loop()
{
  int i;

Then remove the multiple declarations of "i" elsewhere, eg.

Change:

  for (int i = 4; i >= 0; i --) //countdown timer

to:

  for (i = 4; i >= 0; i --) //countdown timer

Effectively it is warning you about multiple redeclarations of "i".

    for (int i = 1500; i >= 1000; i --);
    {

You've accidentally put a ; after the for line.

You've accidentally put a ; after the for line.

and then referencing i after the end of the for loop, which isn't allowed.

Ah, thanks! That stray semicolon really gave me a headache :cold_sweat:

Any decent C++ compiler will warn about that stray semicolon, but unfortunately the Arduino IDE turns most of the gcc compiler warnings off.

Well spotted, PaulS!

Older versions of the compiler would allow the "i" declared in the loop to remain in scope, so it would be valid to do this:

void setup ()
  {
  for (int i = 0; i < 42; i++)
    {
    // whatever
    }
  
  int j = i;      // <------ now raises an error
  }  // end of setup
  
void loop ()  {    }  // end of loop

However more recently "i" is scoped to the loop only, and thus the assignment to "j" fails.

Any decent C++ compiler will warn about that stray semicolon, but unfortunately the Arduino IDE turns most of the gcc compiler warnings off.

Why? That's a perfectly valid thing to do, and I do it often. Especially when traversing to the end of a linked list:

for(ptr=head; ptr->next; ptr=ptr->next);
ptr->next = newelement;

That's a perfectly valid thing to do, and I do it often. Especially when traversing to the end of a linked list

Wouldn't it be easier and faster to keep a pointer to tail?

PaulS:

That's a perfectly valid thing to do, and I do it often. Especially when traversing to the end of a linked list

Wouldn't it be easier and faster to keep a pointer to tail?

faster? yes. easier? no.

You have to always ensure you update said pointer every time to add something to the tail. It just takes one moment of forgetfulness when you don't add the tail pointer updating, and you have a rather nasty bug. Memory-leaks-r-us.

faster? yes. easier? no.

I'll take your word for it. I've never bothered with singly linked lists. Very little extra memory and effort is required to create doubly linked lists that can then be traversed in either direction. With doubly linked lists, you don't have the luxury of forgetfulness.

Standard Template Library.

Then you don't have to re-invent the wheel every time you want a linked list for a different data type.

Fine if you want to use C++ I guess. Not if you either can't or don't want to.

majenko:

Any decent C++ compiler will warn about that stray semicolon, but unfortunately the Arduino IDE turns most of the gcc compiler warnings off.

Why? That's a perfectly valid thing to do, and I do it often. Especially when traversing to the end of a linked list:

for(ptr=head; ptr->next; ptr=ptr->next);

ptr->next = newelement;

Yes but have you ever intentionally written for(LinkedList * ptr=head; ptr->next; ptr=ptr->next); and then immediately followed it with a { ?

As far as I know there is no GCC warning for this kind of mistake anyway.

stimmer:

majenko:

Any decent C++ compiler will warn about that stray semicolon, but unfortunately the Arduino IDE turns most of the gcc compiler warnings off.

Why? That's a perfectly valid thing to do, and I do it often. Especially when traversing to the end of a linked list:

for(ptr=head; ptr->next; ptr=ptr->next);

ptr->next = newelement;

Yes but have you ever intentionally written for(LinkedList * ptr=head; ptr->next; ptr=ptr->next); and then immediately followed it with a { ?

As far as I know there is no GCC warning for this kind of mistake anyway.

Can't say as I have, no, however there is no syntactical reason why that would be wrong.

There is nothing to say that a { HAS to follow a for/while/if etc - it can just be on its own. You can use it to group blocks of code to make it easier to read. I don't know anyone that actually does that, but it's perfectly valid.

majenko:

Any decent C++ compiler will warn about that stray semicolon, but unfortunately the Arduino IDE turns most of the gcc compiler warnings off.

Why? That's a perfectly valid thing to do, and I do it often. Especially when traversing to the end of a linked list:

for(ptr=head; ptr->next; ptr=ptr->next);

ptr->next = newelement;

Yes, it's valid C++, but convention is that if you really want to write a loop with an empty body, you indicate that it is intentional, either by using { }, or by putting a newline or a comment between the ) and the ; .

dc42:

majenko:

Any decent C++ compiler will warn about that stray semicolon, but unfortunately the Arduino IDE turns most of the gcc compiler warnings off.

Why? That's a perfectly valid thing to do, and I do it often. Especially when traversing to the end of a linked list:

for(ptr=head; ptr->next; ptr=ptr->next);

ptr->next = newelement;

Yes, it's valid C++, but convention is that if you really want to write a loop with an empty body, you indicate that it is intentional, either by using { }, or by putting a newline or a comment between the ) and the ; .

Yes, but strip the newlines and the comments, which is generally what the compiler does, and how can it tell the difference? It can't - so no warnings. Neither I, nor the compiler, care what different people do as "convention" - you can't have a warning for something that is perfectly valid, just not correct.

majenko:
you can't have a warning for something that is perfectly valid, just not correct.

That's the entire point of a warning rather than an error. this code is valid:

  if (n = 8) {
    
  }

In fact, that is even used:

int ret;
const char* s = "Hello there", t = "Hello There";
if (ret = strcmp(s, t)) {
  // strings do not match
}
else {
  // strings do match
}

so the compiler's warning says "put parentheses around it to show me you know it's weird."

Something that could be correct but probably isn't shouldn't get a warning unless there's a way of expressing the same thing without getting the warning. So it could be an error for if(statement); {/*...*/} but it could be suppressed by if(statement) { } {/*...*/

WizenedEE:

majenko:
you can't have a warning for something that is perfectly valid, just not correct.

That's the entire point of a warning rather than an error. this code is valid:

  if (n = 8) {

}




In fact, that is even used:


int ret;
const char* s = "Hello there", t = "Hello There";
if (ret = strcmp(s, t)) {
 // strings do not match
}
else {
 // strings do match
}



so the compiler's warning says "put parentheses around it to show me you know it's weird." 

Something that could be correct but probably isn't shouldn't get a warning unless there's a way of expressing the same thing without getting the warning. So it could be an error for `if(statement); {/*...*/}` but it could be suppressed by `if(statement) { } {/*...*/`

So how would you suggest suppressing a warning for

for(ptr=head; ptr->next; ptr++);

?

By the way, the precompiler strips all comments, so putting comments in something is a futile exercise. An empty block gets reduced to an end of statement (;).

Warnings are there for things that are programatically iffy.

You can't have a warning for something that is valid, just because in that one specific situation the programmer used it wrong.

You can't have a warning because the maths you used in a formula is wrong, but you can have a warning if the order of precedence, or the order of assignment, etc, is not clear.

You can't warn the user that they have written the wrong program.

majenko:

WizenedEE:
but it could be suppressed by if(statement) { } {/*...*/

So how would you suggest suppressing a warning for

for(ptr=head; ptr->next; ptr++);

?

umm.. did you read the last sentence of the post you quoted?