3
void main()
{
    extern int i;
    printf("%d\n",i);
}
int i;//definetion
int i=35;//definition

In the above code int i means i=0; and int i=35 means i=35.

So which value will get printed any why the compiler is not giving error of redefinition?

2 Answers2

3

In the ansi standard they call int x; a "tentative" definition.

This is what ansi standard 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. 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.

With examples:

     int i1 = 1;          /*  definition, external linkage */
     static int i2 = 2;   /*  definition, internal linkage */
     extern int i3 = 3;   /*  definition, external linkage */
     int i4;              /*  tentative definition, external linkage */
     static int i5;       /*  tentative definition, internal linkage */
     int i1;   /*  valid tentative definition, refers to previous */
     int i2;   /*  $3.1.2.2 renders undefined, linkage disagreement */
     int i3;   /*  valid tentative definition, refers to previous */
     int i4;   /*  valid tentative definition, refers to previous */
     int i5;   /*  $3.1.2.2 renders undefined, linkage disagreement */



     extern int i1; /* refers to previous, whose linkage is external */
     extern int i2; /* refers to previous, whose linkage is internal */
     extern int i3; /* refers to previous, whose linkage is external */
     extern int i4; /* refers to previous, whose linkage is external */
     extern int i5; /* refers to previous, whose linkage is internal */

In my understanding you can have as many tentative definitions of the same object as you want and at most one definition (with an initializer). If there is no definition, tentative definitions are turned into definition with initializer == 0 at the end of the file.

In other words, the value printed is 35, because there is an initializer.

Marian
  • 7,402
  • 2
  • 22
  • 34
  • if `int i` refers to `int i =35` then we can always replace `extern int i` with `int i` –  Jan 17 '14 at 13:56
  • Not really. If you place `int i` into a header file it will turn into definition (and reserve a space for the variable) at the end of each file including this header and you will get multiple definition problem during linkage. – Marian Jan 17 '14 at 14:03
  • what if I place `int i` before `void main()` and remove `extern int i` from `main()` ....then also the code works –  Jan 17 '14 at 14:03
  • @learner: If you place `int i;` before main and remove `extern int i;` from main it will work in the same way as now. However all this is not what classical C developer would do. A "normal" developer would put `extern int i;` somewhere in a header file and exactly one `int i = 35;` somethere in a code file. – Marian Jan 17 '14 at 14:06
  • how putting `extern int i` in header file will help –  Jan 17 '14 at 14:18
  • @learner: `extern int i;` will not turn into definition at the end of the file and will never reserve place for the variable while you can use this variable in the whole program. At least in any file including this header. – Marian Jan 17 '14 at 14:19
  • but even after adding `extern int i` in header file, it will be required to use `extern int i` in the code as shown in my question> –  Jan 17 '14 at 14:20
  • @learner: As it was told somewhere: A declaration says "there is such a variable somewhere" and definition says: "here it is!". – Marian Jan 17 '14 at 14:22
  • You need to include this header file at the beginning of each code file. In normal case, this header file will contain declarations of many variables not just this one. – Marian Jan 17 '14 at 14:24
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/45477/discussion-between-marian-and-learner) – Marian Jan 17 '14 at 14:24
1

from 6.7.5:

"A definition of an identifier is a declaration for that identifier that: — for an object, causes storage to be reserved for that object; ..."

so both int i; and int i = 35; are definitions (and also declarations since all definitions are declarations).

The difference is that int i = 35; also has an explicit initialiser while int i; is implicitly initilised to 0 (assuming global therefore static storage duration) only if there isn't an external definition:

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

Note that these tentative definitions are not available in c++. (see Appendix C1.2 clause 3.1)

Therefore, in this case the value 35 will be printed since that is the value that i is initialised to.

msam
  • 4,259
  • 3
  • 19
  • 32