41

This code compiles, but I have a run time error in Visual Studio:

Run-time check failure #3 - the variable 'x' is being used without being initialized...

int x = 15;
int main()
{
    int x = x;
    return 0;
}

I don't understand that behavior... in the error box when I click continue the program resumes and x has a corrupted content (like -8556328 instead of 15).

Why does this code work without a problem, and the int array is well declared?

const int x = 5;
int main()
{
     int x[x] = {1,2,3,4};
     return 0;
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302
Aminos
  • 754
  • 1
  • 20
  • 40
  • 19
    You tagged both C and C++. Which did you compile? – underscore_d Oct 01 '15 at 20:43
  • 3
    Some interesting facts: `gcc 4.8.4`, compiles and this program can be run with `-Wall -Wextra -pedantic` turned on. `clang 7.0.0` compiles it, and can be run as is. However if `printf("%d\n", x);` is added after `int x=x;` (I guess any actual usage of `x`), the compiler gives the more friendly warning: `warning: variable 'x' is uninitialized when used within its own initialization [-Wuninitialized]`. `gcc` still compiles and runs it even with the `printf` and printed `0`. However running the program through valgrind gives `Conditional jump or move depends on uninitialised value(s)` – Joakim Oct 01 '15 at 23:32
  • @Joakim: Interesting; thanks for the results. Are GCC and Clang within their rights, i.e. is this canonically undefined behaviour? – underscore_d Oct 02 '15 at 08:08
  • 1
    @underscore_d - C++ doesn't require any diagnostics on uninitialized variables. And the compiler is free to optimize away a variable altogether, especially if it is never really used after the assignment. In fact, "undefined behavior" means that the compiler can do whatever it wishes. – Jirka Hanika Oct 02 '15 at 14:09
  • Yup, I know what UB means, just wanted to check that the standard defined (or rather, omits to define) these particular cases as UB. Thanks for the info – underscore_d Oct 02 '15 at 14:15
  • @underscore_d - UB is entered in C++ if you read it before assigning it. It's not UB if you just leave it indeterminate for some time (or forever - until the end of its scope). During that time, the same stack address might be used for another variable, or...whatever. I think that C is somewhat more specific about allowed behaviors, but it still allows a crash when you read it. – Jirka Hanika Oct 02 '15 at 14:18
  • @underscore_d - Correction: Reading uninitialized variable is not UB only in case you take the address of the variable somewhere. _"If the lvalue designates an object of automatic storage duration that could have been declared with the register storage class (never had its address taken), and that object is uninitialized (not declared with an initializer and no assignment to it has been performed prior to use), the behavior is undefined."_ When the address is taken, this rule still allows, for example, reading the variable twice and seeing different values, maybe even worse things. – Jirka Hanika Oct 02 '15 at 14:33
  • See both [Does initialization entail lvalue-to-rvalue conversion? Is `int x = x;` UB?](http://stackoverflow.com/q/14935722/1708801) and [Has C++ standard changed with respect to the use of indeterminate values and undefined behavior in C++14?](http://stackoverflow.com/q/23415661/1708801) – Shafik Yaghmour Oct 06 '15 at 12:50

4 Answers4

52

x is defined at the left of =.

so in x[x], [x] refer to the global one,

whereas in x = x;, x hides the global x and initializes from itself -> UB.

Jarod42
  • 203,559
  • 14
  • 181
  • 302
35

When you declare a new variable, its name becomes visible right here

int x =
//     ^- there

because it is at that point the variable is fully declared, and as such; its name means something. At this point in time any other (previously declared variable) in a surrounding scope will be hidden.

Filip Roséen - refp
  • 62,493
  • 20
  • 150
  • 196
Bo Persson
  • 90,663
  • 31
  • 146
  • 203
5

There is no scope resolution operator in C, so you may not be able to use

int x = x;

in your program.

Adi
  • 158
  • 1
  • 6
1

please use SRO( Scope resolution operator ::) to tell compiler which x is real x in your mind. As user defined names are mangled( Names are decorated) something like this to avoid ambiguity at it's level, these are just names used by compiler that best suits it

int x = 15;// Real name = gui_x
int main()
{
    int x = x;// lui_x
    return 0;
}

In this way run-time will know which version you are using but to avoid ambiguity it expects from you to use specific names. Sometimes above problem arise where you don't know that you are using already used names. For this C++ has created SRO.
Now in case of array x is address & not integer that stores something, that's why compiler didn't jumbled. You need to write

namespace abc //now all global variables are belongs to this ns abc
int x = 15;// Real name = gui_x
int main()
{
int x = abc::x;// lui_x
return 0;
}