简体   繁体   中英

Extern declaration follows non-extern declaration in same scope

#include <stdio.h>

extern int x;

int main()
{
    int x;
    x = 1;
    printf("%d", x);
}
#include <stdio.h>

int main()
{
    extern int x;
    int x;
    x = 1;
    printf("%d", x);
}

I am learning about extern keyword and I was told that the word extern is used to declare variable and compiler will not allocate for this variable. But when I write 2 codes, the first code run normally and the second has an error. Please help me explain why it has this difference. Thanks.

Conflicting Declarations in Same Scope

When extern int x; appears outside a function, it declares x at file scope. Then, when int x; appears inside the function, it declares a new instance of x that is unrelated to the earlier extern int x; . This is allowed by the C language, so the compiler does not complain about it.

When extern int x; appears inside the function, it declares x at block scope. Then, when int x; appears after it, it attempts to declare a different x in the same scope. This is not allowed by the C standard, so the compiler reports an error.

The extern keyword is not particularly relevant here—the error is caused by the fact that there are two conflicting declarations of the same identifier. For example:

char c;
int main(void)
{
    char d;

    int c; // Allowed, new declaration in new scope.
    int d; // Not allowed, conflicting declaration in same scope.
}

Rules About Declarations

The rules about C declarations have some irregularities due to the history of C development. Consider these declarations at file scope:

extern int x;
int x;

The first declaration does (or does not do) several things:

  • It says x is an identifier for an int .
  • It says x has external linkage, meaning it can be made (during linking of the object modules) to refer to an object named x declared somewhere else.
  • It does not define an int .

For the second declaration:

  • It says x is an identifier for an int .
  • It says x has external linkage (because external is the default for declarations for objects without a storage class specifier like static outside functions).
  • It defines an int . (It is actually a tentative definition , but we will not deal with that here.)

Both of these declarations say x is an identifier for an int and has external linkage. The difference between them is the first does not define an object (it merely says x is a name for an object defined somewhere else) and the second does define an int (so it is the somewhere else). So these declarations do not conflict and are allowed.

On other hand, consider these same declarations inside a function. Then they are at block scope.

Then extern int x; has the same meaning as above: x is an identifier with external linkage for an object defined elsewhere.

But int x; has a different meaning. Instead of saying x has external (or internal) linkage, it says x has no linkage, because no linkage is the default for declarations in block scope. This creates a conflict because C 2018 6.7 3 says an identifier with no linkage shall not be declared more than once in the same scope (and name space, not addressed here) except for typedef names and tags with certain conditions.

Scopes

C has four kinds of scopes:

  • File scope is for declarations outside of functions and lasts to the end of the source file being compiled.
  • Block scope is for declarations inside functions and lasts until the end of a block (discussed below).
  • Function prototype scope is for declarations in the parameters of function prototypes. (For example, in void foo(int n, float a[n][n]); , n and a have function prototype scope.)
  • Function scope is for labels to be used in goto statements.

A compound statement is a list of declarations and statements inside { and } . Each compound statement is a block, which creates a new scope for declarations. The main body of a function is a compound statement that is a block, and it may have additional compound statements inside it, each starting a new scope.

Blocks are also created by switch , if , do , while , and for statements, but they are largely unimportant for the first four of those, as only the for statement provides an opportunity for further declarations. For example, in a for statement, you can write for (int x = 3; x < 20; ++x) , and that creates a new instance of x because the for statement starts a new block.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM