0

I am researching an interesting behavior for two code segments, that give me unexpected behavior.

Describing The behavior

Code segment 1:

#include <iostream>

using namespace std;

int main()
{
    long long n;
    long long m;
    
    // cin >> n;

    cout << m;

    return 0;
}

When I run this (for example in https://www.onlinegdb.com/online_c++_compiler), the value printed in the console (the value inside the variable m) is 0. This is expected and corresponds to the fact that the long long type has a default initialization to 0 (zero initialization).

Code segment 2:

#include <iostream>

using namespace std;

int main()
{
    long long n;
    long long m;
    
    cin >> n;

    cout << m;

    return 0;
}

By uncommenting the line with cin and adding any value, I do not get 0, but rather a different value depending on the number I input for n. Other characteristics of this behavior are:

  1. For different input values for n, we get different values in m.
  2. Each time the same value is given for n, we get the same value in m.
  3. Defining n or m static results in the expected behavior, which is m carrying the value 0.
  4. The same behavior persists if m, n are ints

The unexpected behavior is thus that m does not have a default initialization to 0.

Discussion

My explanation

  1. The uncommented line, cin >> n, creates a new thread for execution.
  2. The new thread creates a new stack to which all local variables are copied.
  3. Since m is not initialized in the original stack, the value it carries is indeterminate in the new stack. It depends on the state of the current stack. But the state of the stack is dependent on the state of the original copied stack, which, in turn, is dependent on the value of the input n.

Issues

My explanation is congruent with characteristic 3. Nevertheless, I do not know how to check for this using a single thread. Moreover, the reason might be something more than stack-related such that even with one and only one thread, the behavior persists. What do you think?

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
  • 6
    *"This is expected and corresponds to the fact that the long long type has a default initialization to 0 (zero initialization)"* - No it doesn't. If you want zero initialization of a primitive you need to specify it explicitly. Otherwise, the value is indeterminate. – StoryTeller - Unslander Monica Sep 30 '21 at 17:23
  • 2
    *This is expected and corresponds to the fact that the long long type has a default initialization to 0 (zero initialization).* That is false. **Default initialization** of fundamental type does **no** initialization. **Value initialization** on the other hand will zero initialize fundamental types. – NathanOliver Sep 30 '21 at 17:25
  • 1
    In your speculation about `cin >> n` creating a new thread of execution (it definitely doesn't), you mention offhand that "`m` is not initialized in the original". Which is actually true, but contradicts your earlier misconception that default initialization for `m` should assign `0` to it. – Nathan Pierson Sep 30 '21 at 17:37
  • Try moving the definitions of `m` and `n` out of main. I think then that you'll get the zero initialization you were expecting – Tim Randall Sep 30 '21 at 18:08
  • Thank you for your answers and clarifications! StoryTeller and NathanOliver - thank you - I can now read on the [difference between default initialization and value initialization](https://stackoverflow.com/questions/8106016/c-default-initialization-and-value-initialization-which-is-which-which-is-ca). NathanPierson - great point! thank you! I need to brush up on my threading. Tim - I was hoping to get insight on the unexpected behavior, not avoid it. Nevertheless, I think you are correct, being that stating "static" in the method avoids the unexpected behavior. – Louie_the_unsolver Oct 02 '21 at 09:52

1 Answers1

4

C++ initialization is super complicated. However, this case is rather simple (confusing terminology aside ;). You are right that both m and n are default initialized. Though, immediately after that your interpretation is rather off. It starts with

This is expected and corresponds to the fact that the long long type has a default initialization to 0 (zero initialization).

Default initialization for long long int is not zero initialization. Actually it is no initialization at all. From cppreference:

Default initialization is performed in three situations:

  1. when a variable with automatic, static, or thread-local storage duration is declared with no initializer;

[...]

and

The effects of default initialization are:

  • if T is a non-POD (until C++11) class type, [... long long is not a class type ...]
  • if T is an array type, [... long longis not an array type ...]
  • otherwise, no initialization is performed: the objects with automatic storage duration (and their subobjects) contain indeterminate values.

Reading an indeterminate value is undefined behavior. Adding or removing seemingly unrelated lines of code changing the output is typical effect of undefined behavior. The output of your code could be anything. It is undefined.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • Thank you for clarifying, @463035818_is_not_a_number ! I have another question following your answer: In your last paragraph, you say that undefined behavior is affected by adding or removing seemingly unrelated lines of code, and that the output of my code can be anything. Nevertheless, every time I input the same 'n' I get the same value in 'm'. So what exactly is "undefined"? It does not seem to be a random value. – Louie_the_unsolver Oct 02 '21 at 09:44
  • 1
    @Louie_the_unsolver see here: https://en.cppreference.com/w/cpp/language/ub. "Compilers are not required to diagnose undefined behavior (although many simple situations are diagnosed), and the compiled program is not required to do anything meaningful." you might see consistent results, the output is not random, the point is that there is no guarantee what output you get. With a different compiler, on a different OS, with different compiler settings, etc, you might get a completey different output – 463035818_is_not_an_ai Oct 03 '21 at 18:04