16

I am confused about the following code:

#include <iostream>

int i = 1;
int main()
{
    int i = i;
    std::cout << "i: " << i << "\n";
    return 0;
}

Output:

i: 0

I had expected running the above code would print 1. Can someone please explain the reason for this strange behavior?

James Ko
  • 29,012
  • 25
  • 114
  • 214
Ren
  • 2,692
  • 1
  • 18
  • 41
  • 24
    When strange things happen, it's usually UB. – Maroun Mar 20 '16 at 14:10
  • 15
    The warning "main.cpp:13:13: Variable 'i' is uninitialized when used within its own initialization: given by a reasonable compiler may be a hint as to the problem. Perhaps jam up your warning levels and heed their advice. – WhozCraig Mar 20 '16 at 14:11
  • 3
    When you assign int i= i;, i gets initialized with the value of i which you just declared, hence an undefined value. – Yves Daoust Mar 20 '16 at 14:20
  • 4
    Please, always compile with `-Wall -Werror` – temoto Mar 20 '16 at 15:34
  • @temoto: none of `g++ -Wall -Wextra`, `clang -Weverything`, MSVC `/Wall /Wextra /Weverything` warns about this. – GingerPlusPlus Mar 20 '16 at 18:16
  • 2
    aside: just in case you are not familiar with [undefined behavior](http://www.slideshare.net/GiorgiMoniava/introduction-to-undefined-behavior-in-c-and-c) – Giorgi Moniava Mar 20 '16 at 18:32
  • @GingerPlusPlus -- I don't have MSVC, but I do have clang and g++, and both of them issue warnings about `i` being used uninitialized. – David Hammen Mar 20 '16 at 19:01
  • @DavidHammen: I guess I just use outdated versions, then. – GingerPlusPlus Mar 20 '16 at 19:18

1 Answers1

62

You are initializing i with itself. The both i's in int i = i; are the inner one not the outer one. This is undefined behavior and you may get 0 or anything may happen.

This is the right way if you want to assign the outer i to the inner i.

#include <iostream>

int i = 1;
int main()
{
    int i = ::i;
    std::cout << "i: " << i << "\n";
    return 0;
}

Live Demo


BTW, You should carefully read all the compiler warnings. If you did you could see the problem yourself:

warning 'i' is used uninitialized in this function

gsamaras
  • 69,751
  • 39
  • 173
  • 279
Humam Helfawi
  • 18,595
  • 13
  • 73
  • 147
  • 13
    To nitpick a bit: " you may get 0 or any other random value in the int range" is not 100% correct. It is UB, thus anything would happen. If his triggers a time portal and this pulls you 100 years into future this would still be valid behaviour for the program. Not that I know a compiler doing this (... which might be caused by the fact that the ones who implemented this disappeared in the future while testing, before they could share their work) – johannes Mar 20 '16 at 17:50
  • @johannes that is a whole new level... Edited thanks! – Humam Helfawi Mar 20 '16 at 18:26
  • 5
    Do you have any snippets from the standard that support the claim that int i = i; is in fact undefined behavior. An uninitialized variable is not undefined behavior it just has an unspecified value. And since this exact construction appears in the standard (3.3.2) with a claim that the value will be indeterminate, I'm highly skeptical that this is UB. – Steve Cox Mar 20 '16 at 19:03
  • @SteveCox I don't think this is undefined behavior because there is no arithmetic being performed. Using `i` as the denominator in a division operation *may* result in undefined behavior depending on various factors. – Corey Mar 20 '16 at 23:36
  • @johannes, there is a difference between unspecified and undefined behaviour. Unspecified means it has to do something vaguely sensible, but not crash, and definitely no time portals. I think this *could* be either undefined or unspecified though, so it'd be nice to see where in the standard it says this. – tobyodavies Mar 21 '16 at 00:51
  • @SteveCox: There's special permission for narrow character types which make the result uninitialized. The example in 3.3.2 uses `unsigned char` which is a narrow character type. But this code uses `int`, ergo it requires lvalue->rvalue conversion on an uninitialized value, which causes undefined behavior. See 8.5p12 "If an indeterminate value is produced by an evaluation, the behavior is undefined except in the following cases" (all cases require a narrow character type) – Ben Voigt Mar 21 '16 at 03:14
  • 2
    @SteveCox: Please see http://stackoverflow.com/q/23415661/103167 – Ben Voigt Mar 21 '16 at 03:23
  • @BenVoigt Thanks for the reference. Looks like this did change in the c++11 standard. i should probably get that – Steve Cox Mar 21 '16 at 15:21