11

I have the following source code which interests me.

#include <stdio.h>
extern int foo;
int foo = 32;

int main()
{
printf("%d", foo);
}

This a perfectly normal piece of code, and when I compile it with

gcc -Wall -Wextra -pedantic foo.c

I get no warnings.

And it seems weird, because a variable is defined both as external, and also global in the same file. I'm quite sure that it's easy to the linker to find the reference for the external variable in the same file, but doesn't it look like a coding error? And if so, why doesn't the compiler warn about this?

LtWorf
  • 7,286
  • 6
  • 31
  • 45
stdcall
  • 27,613
  • 18
  • 81
  • 125

5 Answers5

15

There's nothing weird. You first made a declaration of a variable (you promised the compiler that it exist) and then you actually defined it. There's no problem in that.

Also, by default, all variables that aren't local to functions and aren't defined as static are extern.

Alexey Frunze
  • 61,140
  • 12
  • 83
  • 180
  • first declare then defined can also be seen in function definition like: `void function(int n; char d[n], int n);` Am I correct **?** – Grijesh Chauhan Mar 24 '13 at 13:09
  • @GrijeshChauhan Correct. This is the mechanism that allows creation of programs out of smaller separately compiled parts (object files and libraries). Code and data may be scattered across a number of files. – Alexey Frunze Mar 24 '13 at 13:11
  • I'm so grateful you said that "all variables that aren't local to functions and aren't defined as static are extern". I had assumed the opposite and it was killing me to figure out how to make a variable label defined in C visible to the assembler. – beeflobill Dec 10 '19 at 21:36
8

You seem to misunderstand what extern does. extern simply makes your declaration just a declaration instead of a definition.

int i; //definition of i
extern int i; //declaration of i

It is perfectly normal to have multiple declarations of the same variable, but only one definition should be present in the whole program. Compare this with a function

void f(void); //declaration
void f(void) //definition(and redeclaration)
{
} //definition

In order to use a variable or function, you only need its declaration. Its definition may appear anywhere in the program (the linker will find it). Anywhere can be the same file, another file, or even an external library.

Armen Tsirunyan
  • 130,161
  • 59
  • 324
  • 434
7

And it's seems weired, because a variable is defined both as external, and also global in the same file.

extern int foo;

says: it declares without defining an object of type int named foo.

 int foo = 32;

it declares and defines an object of type int named foo with external linkage.

There is no contradiction and it is valid C code.

ouah
  • 142,963
  • 15
  • 272
  • 331
  • But if foo was actually declared ( as promised by extern ) in some other file, the code `int foo = 32;` would not be correct. –  Mar 24 '13 at 13:07
  • @Armin: `foo` can be declared as many times and in as many files as you like (with or without `extern`), but there cannot be more than one initialisation. – teppic Mar 24 '13 at 13:19
  • @teppic not without `extern`. At the end of a translation unit, the tentative(s) definition(s) will become a real definition. And it is undefined behavior to have multiple definitions of external objects with the same name. – ouah Mar 24 '13 at 13:24
  • @ouah - if you have `int foo;` in one file and `int foo;` in another, it's perfectly fine. – teppic Mar 24 '13 at 13:36
  • @teppic it is undefined behavior. Both tentative definitions will become real definitions at the end of their respective translation unit. And C99 says in 6.9p5 *"If an identifier declared with external linkage is used in an expression [...], somewhere in the entire program there shall be exactly one extern one external definition for the identifier; otherwise, there shall be no more than one."* – ouah Mar 24 '13 at 13:46
  • @ouch - only one definition occurs. "An identifier declared in different scopes or in the same scope more than once can be made to refer to the same object or function by a process called linkage. ... If the declaration of an identifier for an object has file scope and no storage-class specifier, its linkage is external." Your quote means there can be only one definition; not one declaration. – teppic Mar 24 '13 at 14:12
  • @teppic yes definition, not declaration. But your `int foo;` tentative definition will become a real definition in each of your two translation units. Two definitions. – ouah Mar 24 '13 at 14:21
  • @ouah - Only at linkage. If `foo` is already defined, the second `int foo;` is an external declaration, not a definition. – teppic Mar 24 '13 at 14:32
  • @teppic you have two translation units in your example, so this means two definitions (6.9.2p2). – ouah Mar 24 '13 at 14:40
  • @ouah - Hmm. The standard is confusing because it says that `int foo;` at file scope is an external declaration, and that external declarations with the same identifier refer to the same object. – teppic Mar 24 '13 at 14:54
  • @ouah - You're right, these do constitute multiple definitions, but the C standard lists it as widely used and defines the usage: "There may be more than one external definition for the identifier of an object, with or without the explicit use of the keyword extern; if the definitions disagree, or more than one is initialized, the behavior is undefined (6.9.2)." I expect it's because the linker on almost any system will resolve the symbol correctly, but it's not guaranteed in every standard compliant implementation. – teppic Mar 24 '13 at 15:41
  • @teppic yes, this is common enough to be listed as a common extension to C in the non-normative Annex J of the Standard. – ouah Mar 24 '13 at 15:46
  • @ouah - yup, that's the quote I took. I didn't realise this was an extension to standard C as I've never seen a compiler complain about it. – teppic Mar 24 '13 at 15:50
2

The difference is that the former is a declaration -> extern declares a variable and says it will be available somewhere around. You can have as many declarations as you want and the latter is a definition which must be there exactly once.
So there should be no warning and no error.

bash.d
  • 13,029
  • 3
  • 29
  • 42
1

extern is a way to provide visibility to a variable that is defined elsewhere...

extern is like a promise...

in example.h

extern int g;// promises that this will be in the object code to anything that includes example.h

example. c

int g;
Grady Player
  • 14,399
  • 2
  • 48
  • 76