-2
#include <iostream>
using namespace std;

int x = 1;

int main() {
    // int x = 1;   -- same behaviour
    {
        int x = x;
        cout << x << endl;
    }
}

Why does the above program print 0? I thought it should print 1.

Is this expected behaviour as per standard? I'm using g++ (GCC) 12.2.0

Harith
  • 4,663
  • 1
  • 5
  • 20
bhanu015
  • 11
  • 1
  • 6
    _`int x = x;`_ the left side is taken from the current scope (which is uninitialized at that point), thus you're ending up with _undefined behavior_ . – πάντα ῥεῖ Mar 31 '23 at 16:58
  • There is no expected behaviour for this program because the behaviour is undefined. At the scope of `main` the global `x` is not seen – Jabberwocky Mar 31 '23 at 17:00
  • @Gerhardh this is UB for both C and C++, isn't it? – Jabberwocky Mar 31 '23 at 17:01
  • @Jabberwocky IIRC, C has some obscure rule that makes this legal. I don't have a reference though. – HolyBlackCat Mar 31 '23 at 17:03
  • I'm baffled after realising the code actually complies even after removing the global variable declaration. Why allow self assignment in declaration in first place? – bhanu015 Mar 31 '23 at 17:06
  • 1
    Nobody wants to be helpful here. Sigh. The way to do what the title asks for is `int x = ::x;`. – Pete Becker Mar 31 '23 at 17:08
  • @HolyBlackCat Interesting that this could be legal, even when it's pointless. – Jabberwocky Mar 31 '23 at 17:09
  • @PeteBecker the question is pretty unclear, the title says one thing, but the question says something different. – Jabberwocky Mar 31 '23 at 17:10
  • @Jabberwocky -- do you not understand the meaning of "Why does the above program print 0? I thought it should print 1."? – Pete Becker Mar 31 '23 at 17:13
  • thanks @PeteBecker for your pointer on ::x. – bhanu015 Mar 31 '23 at 17:19
  • Reopened. The question is not "Why is `int x = x;` legal (which is what the duplicates answered), but how to initialize the local `x` to the value of the global `x`. – Pete Becker Mar 31 '23 at 18:13
  • The C++ meaning of `int x = x;` is useless, I consider this as a design error. In Lua, the equivalent `local x = x` has a different semantics: *copy to the newly created `x` variable the content of the `x` variable as seen in the previous scope*. And this is useful. You can even write `local x = {x = x}` where each `x` has a different meaning... – prapin Mar 31 '23 at 18:20
  • @PeteBecker I know at this point, that it's not a good idea to reuse variable names because of UBs in cases like this. But in the same spirit of the original question, is there a way to achieve something synonymous to ```int x = ::x``` if previous declaration is not at global scope but at a parent level scope? – bhanu015 Mar 31 '23 at 18:26
  • @bhanu015 -- no. – Pete Becker Mar 31 '23 at 18:27
  • @prapin I really like your reference to Lua. That's the behaviour I expected intuitively. – bhanu015 Mar 31 '23 at 18:48

1 Answers1

2

Let's simplify for a moment:

int x = 1;
void f() {
    int x = 3;
    std::cout << x << '\n';
}

Here, the local x hides the global x, and the output statement writes out the value of the local x, namely, 3. Simple enough.

If you need to use the global x inside that function you can name it with a scope qualifier:

int x = 1;
void f() {
    int x = 3;
    std::cout << ::x << '\n'; // note the :: in front of x
}

Because of the scope qualifiers, ::x refers to the global x (that's what :: means), so the output statement writes out the value of the global x, namely, 1.

Now the weird case:

int x = 1;
void f() {
    int x = x;
    std::cout << x << '\n';
}

Again, the name x hides the global x, so int x = x; initializes the newly-created x with its own value. Which doesn't make sense. And as the comments to the question so helpfully pointed out, the result is undefined behavior.

But since the goal is to initialize the local x with the value of the global x, the answer should now be obvious:

int x = 1;
void f() {
    int x = ::x;
    std::cout << x << '\n';
    ++x;
    std::cout << x << '\n';
    std::cout << ::x << '\n';
}

Now the local x gets initialized with the value of the global x, and the first output statement writes out the value of the local x, namely 1. Just for completeness, after the modification of the value of the local x, the second output statement writes out the new value of the local x, namely 2. The third output statement writes out the value of the global x, which is still 1.

If you're really into confusing yourself, you can hide a name with a nested scope, like this:

void f() {
    int x = 1;
    {
    int x = 2;
    // ??
    }
}

Here, at the line marked // ??, there's no syntax for getting at the x in the outer scope.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165