Home > Blockchain >  Is it well defined to access a variable from an outer scope before it is redefined?
Is it well defined to access a variable from an outer scope before it is redefined?

Time:03-11

This code compiles with no warnings in gcc-11:

    int i{ 2 };
    {
        std::cout << i;   //prints 2
        int i{ 3 };
        std::cout << i;   //prints 3
    }

Is this well defined or it just happened to work?

CodePudding user response:

Yes, it is. The scope of the second i, and therefore the area in which it shadows the first i, is from its declarator(1) down to the end of the enclosing block. It's the same reason why this is invalid:

{
    std::cout << i;
    int i{ 3 };
}

But, of course, this surely won't happen with any of your code because, as a professional developer, you know better than to use one-character variable names(2) for anything other than very short loops, or to reuse variable names in a confusing manner :-)


(1) The standard (C 20) discusses the concepts of "points of declaration", "potential scope", and "scope", in [basic.scope], and this is the definitive place to look for the rules.

Variable names exist between their point of declaration and the end of their block (their potential scope), excluding areas where they are shadowed (shadowing is the difference potential and actual scope).

The point of declaration for int i{3} is effectively between the i and the { (after declaration but before initialisation).

This can lead to subtle issues such as:

int i = 7;
{
    int i {i};
    // Value of i here is indeterminate.
}

and is usually reason enough to avoid shadowing.


(2) You're not paying cold hard cash for each character in your variable names so it's best not to be stingy :-)

CodePudding user response:

Is this well defined or it just happened to work?

It is well-defined. The scope of a variable declared inside a {...} block starts at the point of declaration and ends at the closing brace. From this C 17 Draft Standard:

6.3.3 Block scope      [basic.scope.block]

1     A name declared in a block (9.3) is local to that block; it has block scope. Its potential scope begins at its point of declaration (6.3.2) and ends at the end of its block. A variable declared at block scope is a local variable.


This code compiles with no warnings in gcc-11

That surprises me. The clang-cl compiler (in Visual Studio 2019, 'borrowing' the /Wall switch from MSVC) gives this:

warning : declaration shadows a local variable [-Wshadow]

Using both -Wall and -Wpedantic in GCC 11.2 doesn't generate this warning; however, explicitly adding -Wshadow does give it. Not sure what "general" -Wxxx switch GCC needs to make it appear.

  • Related