1

I recently learned global and local variables in C, and I found this example on the internet(with no clear explanation)

#include<stdio.h>

int x = 50;

int main(){
    int x = 10;
    {
      extern int x;
      printf("global: %d\n", x);
    }
    printf("local: %d\n", x);
    return 0;
}

I did understand that you can make local and global variables in the same program with the same name(and the local var will take preference inside that function or block), and so the result for printf("local: %d\n", x);would be local: 10. But I could not understand how using extern in the code would get the global variable inside a block where a local variable was defined.

I did study how extern works after seeing this but still I couldn't understand: How does 'declaring' a variable(by using extern int x;) inside a block help bring up the global variable?

Thank you in advance

Maxjo
  • 67
  • 3
  • just because you can doesn't mean you should. – stark May 06 '21 at 13:27
  • FYI, while this is an interesting example for educational purposes, you should know it's also *very* weird to use `extern` this way. `extern` declarations are almost always declared near the top of the file, outside any function. The author of the function normally chooses names of local variables that don't conflict with global names or, less often, that intentionally supersede one. In 40 years I've never seen a case or need to declare an `extern` the other way around, to hide a local variable. – James K. Lowden May 06 '21 at 15:20
  • @JamesK.Lowden Very interesting, does that mean I won't likely see these kind of declarations in the real world? – Maxjo May 06 '21 at 15:35
  • 1
    You'll see `extern` plenty at the top of a file. Inside a function, you should report it to the Audubon Society as the sighting of a rare species. – James K. Lowden May 06 '21 at 15:41

3 Answers3

2

Every scope may shadow identifiers from the higher-level scope. extern declaration show the compiler that somewhere else in the code exists variable x having external linkage. This declaration shadows the previous scope variable x definition.

#include <stdio.h>

int x = 50;

int main(){
    int x = 10;
    printf("scope 1: %d\n", x);
    {
      extern int x;
      printf("scope 2: %d\n", x);
      {
          int x = 20;
          printf("scope 3: %d\n", x);
          {
                extern int x;
                printf("scope 4: %d\n", x);
          }
          printf("scope 3 again: %d\n", x);
      }
      printf("scope 2 again: %d\n", x);
    }
    printf("scope 1 again: %d\n", x);
    return 0;
}

https://godbolt.org/z/YPc6jenEG

Program stdout

scope 1: 10
scope 2: 50
scope 3: 20
scope 4: 50
scope 3 again: 20
scope 2 again: 50
scope 1 again: 10

More: How do I use extern to share variables between source files?

0___________
  • 60,014
  • 4
  • 34
  • 74
2

The fact that the declaration extern int x; refers to int x; declared at file scope is an example of how linkage works. An identifier specifying an object or function may have one of the following linkages:

  • Identifiers with external linkage represent the same object or function in any translation unit (i.e. source file and included headers) in the program.
  • Identifiers with internal linkage represent the same object or function in one particular translation unit.
  • Identifiers with no linkage represent a distinct object and only exist in the scope in which they are declared.

In your example, int x; at file scope has external linkage because it was not declared with the static storage class specifier.

int x; declared in the outermost block of the main function has no linkage because there is no storage class specifier on it, so this declaration defines a new object which masks x declared at file scope.

Now you have extern int x; declared in a sub-block inside of main. Because this identifier is declared with extern, it is compared with the prior visible declaration, specifically x declared in block scope above it. Since this prior declaration has no linkage, this new identifier has external linkage (it would have internal linkage if the prior declaration had internal linkage). This is described in more detail in section 6.2.2p4 of the C standard:

For an identifier declared with the storage-class specifier extern in a scope in which a prior declaration of that identifier is visible, if the prior declaration specifies internal or external linkage, the linkage of the identifier at the later declaration is the same as the linkage specified at the prior declaration. If no prior declaration is visible, or if the prior declaration specifies no linkage, then the identifier has external linkage.

And because it has external linkage, it refers to the same object as int x; declared at file scope.

dbush
  • 205,898
  • 23
  • 218
  • 273
  • @0___________ See my edit. The new identifier could have either external or internal linkage depending on the linkage of the prior declaration. – dbush May 06 '21 at 13:27
  • Thanks for the response, It may be obvious for you but why does the code break when I remove the sub-block where `extern int x;` is? – Maxjo May 06 '21 at 15:13
  • 1
    @Maxjo When you have an identifier with no linkage, it can only be defined / declared once. So another declaration in the same scope violates that rule. – dbush May 06 '21 at 15:14
1

Because int x = 50; appears outside a function, it declares an x that has external linkage, which I will discuss below.

Where int x = 10; appears, it declares a new x that hides the previous x of int x = 50;. Since this declaration is inside a function, it has no linkage.

Where extern int x; appears, it declares a third x that hides the previous x of int x = 10;. Although it is inside a function, the extern causes it to have external linkage.

The external linkage of the first x and the third x causes the compiler (or linker) to resolve them to refer to the same object. So the third x refers to the same object as the first x even though it is a different instance of the identifier. (Because the second x has no linkage, it is not linked to the same object in this way.)

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312