4

Referring to the code below:

#include <stdio.h>

int a;
int a;

int main()
{
    int b;
    int b;

    return 0;
}

Why does the compiler (GCC) complain of redeclaration for only variable 'b' and not 'a'?

redef.c: In function 'main': redef.c:19: error: redeclaration of 'b' with no linkage

redef.c:18: error: previous declaration of 'b' was here

Community
  • 1
  • 1
Prabhu
  • 3,443
  • 15
  • 26
  • Just to rule out one totally picky detail: Could this be a unicode issue where the first "a" is latin and the second "a" is cyrillic? – Codor Apr 16 '14 at 12:10
  • Yes. The other question referred here more or less touches on the topic of scope. My interest is also on compiler not saying 'redeclaration' on variable 'a' – Prabhu Apr 16 '14 at 12:17
  • Also see this: [In C,why is multiple declarations working fine for a global variable but not for a local variable?](http://stackoverflow.com/q/15734699/2455888). – haccks Apr 16 '14 at 12:18
  • @haccks, Thanks! That question precisely. – Prabhu Apr 16 '14 at 12:23

3 Answers3

8

It's because a has external linkage and the standard states (C11, 6.2.2/2):

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. There are three kinds of linkage: external, internal, and none.

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.

So, because a has external linkage, both those declarations refer to the same underlying variable. Because b has no linkage, the declaration refer to unique variables and therefore conflict with each other.

Community
  • 1
  • 1
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • So which of the two statements defines the variable `a` - the first one? – ajay Apr 16 '14 at 13:12
  • I think this quote does not establish the legality or illegality of OP's code. It just means that if the code is legal, then both identifiers denote the same object. – M.M Apr 16 '14 at 13:55
  • @Matt, the phrase "if you do A, it means B" very much establishes the legality of A provided B isn't something like "the compiler will generate an error". – paxdiablo Apr 16 '14 at 19:51
1

Quoting the C99 standard §6.9.2 ¶2

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. 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.

Therefore, both the statements

int a;
int a;

constitute tentative definitions. According to the above quoted part, the behaviour is as if the two statements were replaced by

int a = 0;

However, b defined inside main is an automatic variable, i.e., it has automatic storage allocation. There cannot be two definitions of an automatic variable.

ajay
  • 9,402
  • 8
  • 44
  • 71
0

int a; int a; is a tentative definition. From 6.9.2p2:

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. 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.

Tentative definitions are only permitted at file scope.

The reason that int b; int b; is illegal is because of 6.7p3:

If an identifier has no linkage, there shall be no more than one declaration of the identifier (in a declarator or type specifier) with the same scope and in the same name space

Identifiers declared within a function and not static or extern have no linkage, this is describd in 6.2.2p6

The following identifiers have no linkage: an identifier declared to be anything other than an object or a function; an identifier declared to be a function parameter; a block scope identifier for an object declared without the storage-class specifier extern.

M.M
  • 138,810
  • 21
  • 208
  • 365