Xfce4
Xfce4

Reputation: 567

What is the correct interpretation of "extern" keyword in C?

In this page I cannot understand why Example 3 throws an error:

// CODE 1:

extern int var;
int main(void)
{
  var = 10;
  return 0;
}

There are several answers mentioning that var inside main is a local variable. But why would it not be a global variable at the same time. This code below works tough:

// CODE 2:

int var;        // global
int main(void)
{
  var = 10;
  return 0;
}

In the case of multiple files...

... the code below works:

// CODE 3:

// File 1
extern int var;
int main(void)
{
  print("%d",var);
  return 0;
}
----------------

// File 2
var = 4;

... while this one does not:

// CODE 4:

// File 1
extern int var;
int main(void)
{
  print("%d",var);
  return 0;
}
----------------

// File 2
int func(int a) {
    extern int var;
    var = 3;
    return 0;
}

So I could not find a meaningful explanation to the behavior of the extern keyword. How do you explain/ interpret that keyword? Also what should I change in the codes to make them work as intended?

Upvotes: 0

Views: 134

Answers (1)

Eric Postpischil
Eric Postpischil

Reputation: 222292

In C, every definition is a declaration. Some declarations are definitions, and some are not.

The page you link to, has mistakes. One is it says that “Declaration of a variable or function simply declares that the variable or function exists somewhere in the program, but the memory is not allocated for them.” Actually, that is two mistakes, at least. Per C 2018 6.7 5, “A declaration specifies the interpretation and attributes of a set of identifiers…” This does not necessarily mean any object or function with the declared name actually exists in the program. For example, if we include the <stdio.h> header, the fputc function is declared, but, if we never use it, it might never be linked into the program, and so no such function might exist in the program, even in the file executable file. A declaration that is not a definition only tells the compiler about the name (which we call the identifier); it does not convey information about whether something exists.

A second mistake in that sentence is that it says memory is not allocated for the declared variable or function. This is incorrect because each definition is a declaration. C 2018 6.7 5 continues “… A definition of an identifier is a declaration for that identifier that: — for an object, causes storage to be reserved for that object; — for a function, includes the function body…” For example, int x = 3; is a declaration of x, and it is a definition of x, and it causes memory to be allocated for x, but the page you link to says a declaration does not cause memory to be allocated. So the page is wrong.

The rules regarding extern and what is or is not a definition are complicated because C was developed by multiple people doing different things with it. When C was standardized, the committee had to reconcile different practices. As a consequence, there is no single rule for extern.

A note about terminology: A variable is actually two things: an identifier (its name) and an object (the memory that stores a representation of its value).

In your CODE 1, the linked page’s Example 3, extern int var; is a declaration that is not a definition. There is no definition. If an identifier with external linkage is used in an expression, there must be exactly one external definition of it in the program (by C 2018 6.9 5). Since there is no external definition, the linker complains.

There are several answers mentioning that var inside main is a local variable.

If an identifier is declared inside a block, such as the { … } that forms the body of a function, then effects of the declaration are local to that block. If an identifier is declared outside of any function, the effects of the declaration continue through the rest of the file being compiled, except where they are hidden by a nested declaration.

If var is declared outside of any function and before main, and then we use that identifier inside main without declaring it again, that use of var refers to the previous declaration. It does not create or refer to a new local object named var.

But why would it not be a global variable at the same time.

At any one point in source code, an identifier refers to at most one thing.

.. the code below works:

// File 2 var = 4

var = 4 is not proper C code because it does not have a semicolon. If it were var = 4;, some compilers might accept this outside a function, but it is archaic. In modern C, it should have a type, such as int var = 4;. That would then be a proper definition of var. If your compiler accepted var = 4; outside a function, you should be aware it is accepting old code, and it would be preferable to use switches to tell the compiler to require modern C code.

Upvotes: 1

Related Questions