1

I found this question, the same static variable in C has been declared twice in the same scope but there is no compilation error in the code. How is this so?

#include<stdio.h>
static int i = 90;
int main(){
    printf("%d", i);
    return 0;
}
static int i;
  • For fun try to ad an initialiizer to the second line.... – Support Ukraine Dec 24 '21 at 06:36
  • 2
    The first is a definition. The second is a **tentative definition**. [Here's a similar question](https://stackoverflow.com/questions/33200738) that has more info about tentative definitions. Long story short, tentative definitions exist for backwards compatibility with old (pre-1989) compilers, and should not be used in new code. – user3386109 Dec 24 '21 at 06:48
  • 1
    Does this answer your question? [What is the rationale behind tentative definitions in C?](https://stackoverflow.com/questions/33200738/what-is-the-rationale-behind-tentative-definitions-in-c) – justANewb stands with Ukraine Dec 24 '21 at 07:29
  • FYI, regard the “global scope” in the title, C does not have a global scope (one visible throughout the entire program). Those declarations are *external* (outside of any function) with *internal linkage* and *file scope* (visible in the rest of the translation unit). Identifiers with *external linkage* can be used in multiple translation units, but that differs from global scope because it requires a declaration in each unit and is achieved by linkage, not scope. – Eric Postpischil Dec 24 '21 at 09:50
  • Do not tag both C and C++ except when asking about differences or interactions between the languages. Pick one tag and delete the other. – Eric Postpischil Dec 24 '21 at 15:44

1 Answers1

3

Declarations do not necessarily define objects (reserve memory for them). Fundamentally, a declaration describes an identifier. For example:

  • extern int x; describes an object named x but does not reserve memory for it.
  • typedef char foo; describes a type named foo.
  • struct foo { int x; } describes a structure type tagged foo.

Some declarations also define objects. For an external declaration (here, “external” means it appears outside of any function), C 2018 6.9.2 1 says:

If the declaration of an identifier for an object has file scope and an initializer, the declaration is an external definition for the identifier.

So static int i = 90; at file scope both declares and defines i.

However, static int i; does not define i, because it has no initializer.

C 2018 6.9.2 2 says:

A declaration of an identifier for an object that has file scope without an initializer, and without a storage-class specifier or with the storage-class specifier static, constitutes a tentative definition

This says static int i; is a tentative definition. Although the word “definition” appears in that name, it is not a definition (like a prospective employee is not yet an employee and might never be).

C 2018 6.9.2 2 goes on to say:

… If a translation unit contains one or more tentative definitions for an identifier, and the translation unit contains no external definition for that identifier, then the behavior is exactly as if the translation unit contains a file scope declaration of that identifier, with the composite type as of the end of the translation unit, with an initializer equal to 0.

So, if the translation unit did not contain the definition static int i = 90;, then the tentative definition static int i; would cause a definition to be created. However, that is not the case, so this sentence does not apply. static int i; remains a tentative definition, which is just a declaration. It is not a second definition of i, so there is no violation of the rule that there shall be no more than one external definition of an identifier with internal linkage (C 2018 6.9 3).

These rules about tentative definition grew around historic practice of common variables, which, in FORTRAN, would be declared in multiple translation units, and the linker would resolve all declarations of the same name to a single object in the executable program. If we were redesigning C from scratch today, we would likely create a clearer grammar for declarations and definitions.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312