11

I noticed that if I declare a global variable multiple times the compiler does not even output a warning.

However if I declare a local variable in a function multiple times, for example, the gcc compiler outputs an error and does not compile the file. (I ask in terms of gcc, but this is more a general language design question, not a question about gcc, because I think it is likely other compilers behave similar).

What is the explanation for this behavior?

3
  • Just to be sure, your global variable, had always the same type right ?
    – Walfrat
    Commented Oct 4, 2017 at 14:40
  • @Walfrat Yes the variable is always declared of the same type. If two variables of the same name but with different type are declared globally the the gcc outputs error "conflicting types for a (variable)"
    – yoyo_fun
    Commented Oct 4, 2017 at 14:48
  • 3
    You cannot declare a local variable even once. All you can do is define it. Declaring a variable is telling the compiler what it is. Defining a variable is telling the compiler to allocate memory for it. You must define all variables. In C, a definition of a global variable can be used for a declaration multiple times. But if the program only has extern int x;, which is a declaration, the compile will abort since there is no place where memory is allocated to the variable. Commented Oct 25, 2017 at 11:46

2 Answers 2

14

@msc gives a good introduction into the rules behind this behavior.

I noticed that if I declare a global variable multiple times the compiler does not even output a warning.

C has three kinds of global declarations for objects, namely those that are (and I'm glossing over static here):

  1. declarations that are not definitions — extern int a;
  2. declarations that are also definitions — int a = 3; or extern int a = 3;
  3. tentative definitions — int a;

Multiple declarations of type 1 & 3 are allowed, while at most one (type 2) definition is allowed.


What is the explanation for this behavior?

If you're also asking about motivation for these rules, it is support for separate compilation. (See translation unit).

In order to break a program into multiple files separately compiled, we need a few features, namely (a) being able to declare without necessarily defining, and, (b) forward declaration.

Within one translation unit we need to be able to refer to global functions and data in another translation unit.  And we'd also like some error checking, here, to discover missing definitions, and erroneous duplicate definitions.

Sometimes, in the same translation unit, we declare a global, and then define it later.  This can happen if we need a forward declaration for some reason, or if we use a common header file (that provides declarations) within the one translation unit that also offers explicit definitions.

Since separate compilation in C applies by linking global functions and data together, these features are required at the global level but not at the local level.

As @msc points out, none of this is necessary for local variables as they have no linkage.

C (like many other languages) does not provide linkage for local variables as the language does not attempt to support a single function spanning multiple separate translation units.

(Of course, you can have a function span multiple source files, but not multiple translation units.)

A tentative definition works just like a declaration in that it is allowed in multiple translation units (and also combines nicely with other declarations).  However, if there is no (non-tentative) definition for the identifier in the whole program, the set of (one or more) tentative definitions across multiple translation units (for one identifier) is taken as a definition for the object whose initializer is zero.

This can be implemented by putting these into the .BSS Section with the proper size and alignment; the linker will either match them to the true definition if found, or else match them to each other, giving them zeroed out space in BSS.


The notion of separate compilation can be supported entirely without the feature of tentative definitions — I think tentative definitions are there mostly for historical reasons.  (I'm not saying they're not useful, just if the language were created today, this might seen as unnecessary and hence not be offered.)

Some purposefully avoid tentative declarations, with the argument that a missing definition should produce a linkage error — silently initializing with zero is error prone so it is better to have a real error message making the programmer address the initialization explicitly.

0
11

According to coding-guidelines :

In the set of translation units and libraries that constitutes an entire program, each declaration of a particular identifier with external linkage denotes the same object or function. Within one translation unit, each declaration of an identifier with internal linkage denotes the same object or function. Each declaration of an identifier with no linkage denotes a unique entity.

The local variable has no linkage. so there is a name Collision occurs. So, multiple declaration of local variable not possible.

The global variable has external linkage. So, multiple declaration of global variables is possible.

2
  • 7
    This answer is fine, however, the obvious follow-up question then is: what is the rationale behind this definition?
    – Doc Brown
    Commented Oct 4, 2017 at 12:09
  • With many C quirks, the rationale is "pre-standard C compilers just did it this way". If you look at the complexity of "tentative definition", it's pretty likely that this is the case here. Commented Oct 6, 2017 at 8:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.