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

    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?

majenko:
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.

Only if the preprocessor (or precompiler as you call it) is a separate program from the main compiler, which is rarely the case these days.

majenko:
An empty block gets reduced to an end of statement (;).

It may be treated in the same way as end-of-statement in some contexts, but the compiler knows the difference, so it is easy for the compiler writter to generate a warning in one case but not in the other.

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

Rubbish. There are very many things that are valid in C++ but symptomatic of possible or likely errors, and all good C++ compilers can warn about many of them. You can choose to run the compiler at its minimum warning level and see none of these warnings, or the maximum warning level and see all of them, or somewhere in between. See Warning Options (Using the GNU Compiler Collection (GCC)) for the warning options supported by the gcc compiler used by the Arduino IDE. In particular, note the following:

-Wall
This enables all the warnings about constructions that some users consider questionable, and that are easy to avoid (or modify to prevent the warning), even in conjunction with macros.

An if, while, for, etc does not "own" the { and }. It merely expects a valid statement.

; is a valid statement.

moveServoToPosition(90); is a valid statement.

{ moveServoToPosition(90); } is a valid statement.

{ } is a valid statement.

The { and } merely convert the containing statements into a single compound statement as seen by the parent layer (the if, while, whatever).

While I agree that an if statement with no body (if(x==3):wink: is syntactically correct, it is pointless, and yes a warning "If without body" could be generated. However, we're not arguing about ifs here - if was introduced about half way through the discussion by WizenedEE.

The code

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

and the code

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

are both perfectly syntactically correct, and in some circumstances are programatically correct as well - i.e., they are exactly what the programmer intended.

There is no way for a compiler to know what a programmer intends.

If you want to start forcing a { } to indicate an intentional empty body, then two things are happening:

  1. You are forcing a coding style on someone. This is not something that C does. Python imposes coding styles. COBOL imposes coding styles. Upper management impose coding styles. C doesn't, it never has, and it never will.

  2. It will break the C specification, which states that the above code is valid.

And then, will you warn about:

for(x=0; x<10; x++)
  doSomething(x);

just because the doSomething(x) isn't inside a { and } ?

This enables all the warnings about constructions that some users consider questionable, and that are easy to avoid (or modify to prevent the warning), even in conjunction with macros.

None of the above three chunks of code are in any way questionable, vague, or otherwise suspect. They are perfectly valid.

Modifying them to "prevent the warning" involves things like adding extra brackets around assignments, etc - not changing the whole structure of the C language!