0
#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.

chqrlie
  • 131,814
  • 10
  • 121
  • 189
dat doan
  • 15
  • 3
  • Case 1: the local variable `x` hides the global variable. The global is never referenced. Case 2: you tell the compiler that `x` is both global and local in the same scope. You can't do that. – Jonathan Leffler Feb 06 '21 at 14:43
  • So do you mean that 'extern' keyword is used to declare a global variable ? – dat doan Feb 06 '21 at 14:51
  • "an error" is not very descriptive – klutt Feb 06 '21 at 14:52
  • Have you looked at: https://stackoverflow.com/questions/856636/effects-of-the-extern-keyword-on-c-functions ? – babon Feb 06 '21 at 14:55
  • here is this error: "error: redeclaration of 'int x' " – dat doan Feb 06 '21 at 14:57
  • Yes, more or less. The `extern` says it exists but is defined somewhere else (a definition elsewhere in the same translation unit (TU) or in another TU. The variable definition must have file scope, I think. (You are dealing with esoteric and obfuscated code if there is a way for the variable not to have file scope.) Depending on circumstances, the variable might be static (invisible outside the TU) or “global” (visible outside the TU). – Jonathan Leffler Feb 06 '21 at 15:35

1 Answers1

3

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.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • I learn that when ```extern int x``` , compiler won't allocate for ```x``` so I can't use ```x``` and I try to do something to 'define' ```x```. How can I do to use ```x``` if I have ```extern int x``` before ? – dat doan Feb 06 '21 at 15:12
  • @datdoan: To provide a definition for `x` when `x` has been declared with external linkage, provide an external definition for it. An external definition is one that is external to (outside of) any function. In other words, put `int x = 0;` at file scope, outside any function. – Eric Postpischil Feb 06 '21 at 15:15
  • Why did you think it was necessary to reopen and answer this question? What about the two prior Q&A that I linked (https://stackoverflow.com/q/14335742 and https://stackoverflow.com/q/45724358) did you not think was adequate? Your answer seems to tread the same ground to me. Is there some nuance that I'm missing? – Cody Gray - on strike Feb 07 '21 at 05:50
  • @CodyGray: The problem in this question is caused by disallowed redeclarations in the same scope. The difference between the two code samples is the scope of the first declaration. Your first purported duplicate does not ask about scope or redeclarations at all, and its answers speak to `scope` only as to how it affects the semantics of `extern`; no mention is made of disallowed redeclarations. The second question asks about an `extern` declaration after another declaration, which does not exist in this question, where `extern` only appears first. So neither answers this question. – Eric Postpischil Feb 07 '21 at 11:06
  • Are we looking at the same answers? Ciro Santilli's answer clearly describes this precise case, the same one described in your answer, under the subject heading "prior declaration specifies no linkage". It uses the word "declaration" about a dozen times in the answer. I am puzzled at how you can claim that the duplicate Q&A doesn't talk about redeclarations. dbush's answer to the second question clearly states the same thing. As you said yourself, the order is not relevant, because the `extern` is not relevant: the problem is the redeclaration. – Cody Gray - on strike Feb 07 '21 at 11:14
  • @CodyGray: In that passage, the example shown includes a disallowed declaration, but the passage fails to state that! It says `extern int i` after `int i` in the same scope is the same as `extern int i` by itself, which is wrong because the latter has defined behavior and the former has undefined behavior due to the constraint violation (C 2018 6.7 3). In addition to being wrong, the passage is not speaking to when redeclarations are allowed and when they are not and does not even mention that. That is the issue here, not, in spite of the title, how `extern` behaves. – Eric Postpischil Feb 07 '21 at 11:25
  • @CodyGray: First, that question asks about `extern` following non-`extern`, which is not an issue at all in this question; there is no appearance of `extern` after non-`extern`. Even if some answer to a question happened to answer a different question, that does not make the question a duplicate: A student looking for the answer to “What is X?” would not expect to find it in a question “What is Y?”. Going on, dbush’s answer does not explain that identifiers with no linkage cannot be redeclared in the same scope except for certain cases involving `typedef` and tags. So it does not answer this. – Eric Postpischil Feb 07 '21 at 11:38
  • @CodyGray: On top of that, it is wrong in the reason it gives for the error message. It says “locals can't have external linkage.” Certainly an identifier with block scope can have external linkage. It would be true that an identifier for an object defined “locally” cannot have external linkage, but that is not relevant, as `extern int i` does not define an object. So its reason that `extern int i` is not allowed after `int i` is wrong. – Eric Postpischil Feb 07 '21 at 11:39
  • It doesn't matter what someone might *expect* to find. That's not what a duplicate closure means: it isn't a slap on the wrist or a commentary on someone's research effort. It merely says: the answer to your question can be found here. If the answers are the same, then the question is a duplicate. That's why we have people with subject-matter expertise proposing duplicates, because they're the ones best able to assess whether something is a duplicate, going on far more than simply matching the words in the question. – Cody Gray - on strike Feb 07 '21 at 11:43
  • And, if there's so much wrong in the existing answers, that's *even more reason* why we should close this as a duplicate so that you can post an answer on the other questions with the correct information. – Cody Gray - on strike Feb 07 '21 at 11:44
  • Re “It merely says: the answer to your question can be found here”: I am not aware of such a guideline. But it is irrelevant, as the answers to your purported duplicates in fact do not answer this question. Re “so much wrong in the existing answers… so that you can post an answer on the other questions with the correct information”: No, the fact that other answers to non-duplicate questions have mistakes is not a reason to close as a duplicate. – Eric Postpischil Feb 07 '21 at 11:48