Variable value change was not expected

I am trying to understand why I get different results from this demo sketch when I make changes like making the variable "y" global, or replacing "if (x > 3)" with "if (1)".

First, defining "y" within loop().

  int x = 6;

  void setup() {
  Serial.begin(9600);
  delay(500);
  }

  void loop() {
  int y;                // <------------ 
  prt('A', x, y);       // A 6 0

  if (x > 3) {
    prt('B', x, y);     // B 6 0
  }

  else {
    prt('C', x, y);     // nothing printed here
    if (1) y = 1;       // how can y become 1 here ?
    prt('D', x, y);     // nothing printed here
  }

  prt('E', x, y);       // E 6 1 (y not expected)

  while (1);
  }

  void prt(char i, int x, int y) {
  Serial.print(i);
  Serial.print("\t");
  Serial.print(x);
  Serial.print("\t");
  Serial.println(y);
  }

Then with "y" as a global variable.

  int x = 6;
  int y;            // <------------

  void setup() {
  Serial.begin(9600);
  delay(500);
  }

  void loop() {

  prt('A', x, y);       // A 6 0

  if (x > 3) {
    prt('B', x, y);     // B 6 0
  }

  else {
    prt('C', x, y);    // nothing printed here
    if (1) y = 1;
    prt('D', x, y);    // nothing printed here
  }

  prt('E', x, y);       // E 6 0 (y expected)

  while (1);
  }

  void prt(char i, int x, int y) {
  Serial.print(i);
  Serial.print("\t");
  Serial.print(x);
  Serial.print("\t");
  Serial.println(y);
  }

And then "y" defined within loop() again, but now with "if (x > 3)" replaced with "if (1)".

int x = 6;

void setup() {
  Serial.begin(9600);
  delay(500);
}

void loop() {
  int y;                // <------------
  prt('A', x, y);       // A 6 0

  if (1) {              // <------------
    prt('B', x, y);     // B 6 0
  }

  else {
    prt('C', x, y);    // nothing printed here
    if (1) y = 1;
    prt('D', x, y);    // nothing printed here
  }

  prt('E', x, y);       // E 6 0 (y expected)

  while (1);
}


void prt(char i, int x, int y) {
  Serial.print(i);
  Serial.print("\t");
  Serial.print(x);
  Serial.print("\t");
  Serial.println(y);
}

How can "y" become 1 in the first example ?
How can this be cured by any of the two changes ?
I am asking because if I do not understand why this is happening in a small test sketch, then I may get into real trouble further down the road.

IDE 1.8.16, same result with different MCUs.

Always initialise variables is a good idea. Try your code with

int y = 0;
1 Like

If the variable is global, and is of type int, the initial value will be 0.

If the variable is local, the initial value will be whatever was in the memory location that the variable is assigned to. That is, some random garbage.

Always best to give variables an initial value.

In the first example, the initial value of y is 0.
The question is why does it change to 1 in the "else" statement (that is not executed).
I guess it is related to compiler code optimization but not sure how.

This is just a demo sketch and I can easily fix it. But what is happening here, and why ? That is what I would like to learn, because I am curious.

Sorry... I missed your original question.

... and yes I agree, that is pretty weird. I can't explain it. After a bit of playing around I also suspect that it is the compiler optimisation that is somehow getting confused and setting the variable value in subsequent statements because it was not initialised.

Maybe someone else on here can explain.

i'm puzzled

i get following running code on my laptop

 A       6      0
 B       6      0
 E       6      0
#include <stdio.h>

void
prt (
    char  c,
    int   a,
    int   b )
{
    printf (" %c  %6d %6d\n", c, a, b);
}

int x = 6;
int main ()
{
    int y;                // <------------
    prt('A', x, y);       // A 6 0
    if (x > 3) {
        prt('B', x, y);     // B 6 0
    }
    else {
        prt('C', x, y);     // nothing printed here
        if (1) y = 1;       // how can y become 1 here ?
        prt('D', x, y);     // nothing printed here
    }
    prt('E', x, y);       // E 6 1 (y not expected)

    return 0;
}

perhaps this is an example of "undefined behavior"

Here is some more weird behaviour. This is a narrowed down part of my current project:

void setup() {
  Serial.begin(115200);
  Serial2.begin(9600, SERIAL_8N1, 4, 13);
  delay(5000);
  Serial.println("ready");        // prints "ready"
}

void loop() {
  uint8_t _snap;
  bool _formatFS;
  uint8_t _nightMode;
  int Rx = 0;
  int x = 0;

  if (Serial2.available()) {
    Rx = (Serial2.read());

    if (Rx == 6) {
      Serial.println('6');        // prints 6
      //x = 6;                    // (use case 1)
      x = Rx;                     // (use case 2)
    }

    if (x > 3) {
      _snap = (0xc & x) >> 2;
      _nightMode = (3 & x);
      Serial.println("A: ");       // prints A
      Serial.println(x);           // prints 6
      Serial.println(_snap);       // prints 1
      Serial.println(_nightMode);  // prints 2
    }

    else if ((3 & x) == 3) {
      Serial.println("B: ");       // prints nothing
      _formatFS = true;
    }

    if (_formatFS) {
      Serial.println("C: ");      // prints C (case 2 only)
      Serial.println(x);          // prints 6 (case 2 only)
      Serial.println(3 & x);      // prints 2 (case 2 only)
    }
    while (1);
  }
}

In this example, I receive one byte (= 6) via Serial2 in "Rx = (Serial2.read());"
If I use this Rx variable all the way down, I will get this printout:
ready
6
A:
6
1
2
C:
6
2

Same thing if I copy Rx to x and use x in the code instead (use case 2 in the above example).

But if I hard code x to 6 (use case 1), this is the (correct) result:
ready
6
A:
6
1
2

Rebooted pc (Win10), nothing changed.
Maybe time to reinstall IDE ?

No seen the difference from the first example. Variable not initialised resulting in undefined behaviour.

So you can invent many such options, but I don’t see the point in studying them. The correct approach is to initialise all (or at least local) variables and there will be no such miracles

sorry for being rude, but it's time to learn C/C++.
Your programs work as described in the standard

(removed)

The last three lines of the output below has been printed because the uninitialised value of _formaFS. But I don't see a errors more.

You are right, thanks for pointing that out.
What bothered me was that _formatFS was initialized to false "by itself" in use case 1 but not in use case 2.

By not initializing the variable, you have one chance in 256 that the boolean will be true. And a 255 in 256 chance the boolean will be false.

but isn't it vice versa?
0 - false
not 0 - true

Don't think so.

true is often said to be defined as 1, which is correct, but true has a wider definition. Any integer which is non-zero is true, in a Boolean sense. So -1, 2 and -200 are all defined as true, too, in a Boolean sense.

https://www.arduino.cc/reference/en/language/variables/constants/constants/

1 Like

Thank you for the correction.

Interesting, thanks.
Even more interesting to me is that a non-initialized variable may change to any valid value any time until it is properly set for the fist time. As can be seen in my first example where int y decides to change from 0 to 1.

That is because it only a TEMPORARY variable and it's location may be different every time "loop()" is executed.

1 Like

I am happy to have learned something important today.
Thank you all for your time and support !

sorry, do you can confirm it with links to something ... manuals, books..?