External and tentative definitions - cppreference.com

Tentative Definition

A variable declaration with external or internal linkage, no extern specifier, and no initializer is a tentative definition. For example, 1 2

int x;
 
int main(void) {
  return x;
}

If a variable is tentatively defined and not otherwise defined in the same translation unit, it is implicitly initialized to zero.

However, if a file contains both a tentative definition and an explicitly initialized definition, the explicit definition takes precedence:

int x;
 
int main(void) {
  return x; // 3
}
 
int x = 3;

In the above case, the first line is treated as declaration instead.

Although it is invalid to define a variable multiple times, it is fine to have multiple tentative definitions:

int x;
int x; // tentative definition, allowed
extern int x; // declaration, allowed

Note that a tentative definition is only tentative in the translation unit where it appears. It can still conflict with definition in other files (i.e. ODR violation). For example:

File 1:

int var = 4;

File 2:

int var;
 
int main(void) {
  return var;
}

We will have an ODR violation and the behavior is undefined. 1

Footnotes

  1. Writing a C compiler chapter 10 2

  2. C23 Standard Draft 6.9.3