0

Here I have two files externdemo1.c and externdemo2.c.In the first file,I have declared and initialized a character array arr at file scope.But I have declared it in the second file externdemo2.c without the extern keyword and made use of it there in the function display(). Here are my confusions arising from it.Please answer these three:

 //File No.1--externdemo1.c

#include<stdio.h>
#include "externdemo2.c"

extern int display();
char arr[3]={'3','4','7'};
//extern char arr[3]={'3','4','7'};

//extern int main()
int main()
{
    printf("%d",display());
}


//File No.2--externdemo2.c

char arr[3];

int display()
{
    return sizeof(arr);
}

1) Why does the program compile fine even though I have declared arr without the extern keyword in externdemo2.c?I had read that the default linkage of functions is external,but I am not sure if that's so even for variables.I only know that global variables have extern storage class.

2) What is the rigorous difference between extern storage class and extern linkage.I badly need a clarification about this.In the first file,where I have defined the array arr,I haven't used the keyword extern, but I know that it has extern storage class by default.But in the second file, isn't there any default extern ,storage class or linkage,about the global variable arr,ie, in externdemo2.c?

3) Check the commented out line in the first file externdemo1.c.Just to test it, I had used the line extern char arr[3]={'3','4','7'};.But it gives the error 'arr' initialized and declared 'extern'.What does this error mean? I have also mentioned a commented line extern int main(),but it works fine without error or warning.So why can we use extern for a function even though a function is extern by default,but not for a variable,like arr here?

Please take some time to bail me out over this.It will clear most of my lingering doubts about the whole extern thing.It will be immense help if you can answer all 3 bits 1),2) and 3). Especially 3) is eating my brains out

Rüppell's Vulture
  • 3,583
  • 7
  • 35
  • 49

3 Answers3

2

Main questions

  1. Basically, because you've included the source of externdemo2.c in the file externdemo1.c.

  2. This is the big question. Because there is no initializer, the line char arr[3]; in externdemo2.c generates a tentative definition of the array arr. When the actual definition with initialization is encountered, the tentative definition is no longer tentative — but neither is it a duplicate definition.

    Regarding extern storage class vs extern linkage...Linkage refers to whether a symbol can be seen from outside the source file in which it is defined. A symbol with extern linkage can be accessed by name by other source files in which it is appropriately declared. To the extent it is defined, extern storage class means 'stored outside of the scope of a function', so independent of any function. The variable defined with exern storage class might or might not have extern linkage.

    Because it is not defined with the keyword static, the array arr has extern linkage; it is a global variable.

  3. With the commented out line uncommented out, you have two definitions of one array, which is not allowed.

I observe that you must be compiling just externdemo1.c to create a program — the compiler is including the code from externdemo2.c because it is directly included. You can create an object file from externdemo2.c. However, you cannot create a program by linking the object files from both externdemo1.c and externdemo2.c because that would lead to multiple definitions of the function display().

Auxilliary questions

I have placed both files in the [same directory]. If I don't include the second file in the first, then when I compile the first file it gives the error undefined reference to display. Since I have used extern for that function in the first file, isn't the linker supposed to link to it even if I don't include the second file? Or the linker looks for it only in default folders?

There are a couple of confusions here. Let's try dealing with them one at a time.

Linking

The linker (usually launched by the compiler) will link the object files and libraries that are specified on its command line. If you want two object files, call them externdemo1.obj and externdemo2.obj, linked together, you must tell the linker (via the build system in the IDE) that it needs to process both object files — as well as any libraries that it doesn't pick up by default. (The Standard C library, plus the platform-specific extensions, are normally picked up automatically, unless you go out of your way to stop that happening.)

The linker is not obliged to spend any time looking for stray object files that might satisfy references; indeed, it is expected to link only those object files and libraries that it is told to link and not add others at its whim. There are some caveats about libraries (the linker might add some libraries not mentioned on the command line if one of the libraries it is told to link with has references built into it to other libraries), but the linker doesn't add extra object files to the mix.

C++ with template instantiation might be argued to be a bit different, but it is actually following much the same rules.

Source code

You should have a header, externdemo.h, that contains:

#ifndef EXTERNDEMO_H_INCLUDED
#define EXTERNDEMO_H_INCLUDED

extern int display(void);

extern char arr[3];  // Or extern char arr[]; -- but NOT extern char *arr;

#endif /* EXTERNDEMO_H_INCLUDED */

You should then modify the source files to include the header:

//File No.1--externdemo1.c

#include <stdio.h>
#include "externdemo.h"

char arr[3] = { '3', '4', '7' };

int main(void)
{
    printf("%d\n", display());
    return 0;
}

and:

//File No.2--externdemo2.c

#include "externdemo.h"

int display(void)
{
    return sizeof(arr);
}

The only tricky issue here is 'does externdemo2.c really know the size of arr?' The answer is 'Yes' (at least using GCC 4.7.1 on Mac OS X 10.8.3). However, if the extern declaration in the header did not include the size (extern char arr[];), you would get compilation errors such as:

externdemo2.c: In function ‘display’:
externdemo2.c:7:18: error: invalid application of ‘sizeof’ to incomplete type ‘char[]’
externdemo2.c:8:1: warning: control reaches end of non-void function [-Wreturn-type]
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • I have placed both files in the well-known Windows folder "My documents".If I don't include the second file in the first, then when I compile the first file it gives the error `undefined reference to display`.Since I have used `extern` for that function in the first file, isn't the linker supposed to link to it even if I don't include the second file?Or the linker looks for it only in default folders? – Rüppell's Vulture May 07 '13 at 03:26
  • **THANK YOU**.A **GRANDSLAM** answer.That is exactly what I needed for a long question like mine.It will take me a while to digest what you said,but I can see you have looked into all my concerns. – Rüppell's Vulture May 07 '13 at 03:48
  • Just this much Mr.Leffler.GUI compilation has spoiled me.Can you tell me what is the command using which we can compile the first file `externdemo1.c` in gcc so that the linker links to the object file of `externdemo2.c` if we don't include the second file in the first? – Rüppell's Vulture May 07 '13 at 04:06
  • There are a couple of options. (a) `gcc -o externdemo externdemo1.c externdemo2.c`, or (b) `gcc -c externdemo1.c; gcc -c externdemo2.c; gcc -o externdemo1 externdemo1.o externdemo2.o`. I'm assuming the extension of the object files is `.o`; if it is `.obj`, make the appropriate changes to the link line. – Jonathan Leffler May 07 '13 at 04:10
0

Your program looks a bit err. To me the #include "externdemo2.c" line appears invalid.

Following is the correction I have made and it works.

    //File No.1--externdemo1.c

    #include <stdio.h>

    extern char arr[3];

    extern int display();

    int main()
    {
        printf("%d", arr[0]);
        printf("%d",display());
    }

    //File No.2--externdemo2.c


    char arr[3]={'3','4','7'};

    int display()
    {
        return sizeof(arr);
    }

Please follow the below links for better understanding:

Community
  • 1
  • 1
Kajal Sinha
  • 1,565
  • 11
  • 20
  • It's perfectly 'valid' — very unorthodox, but syntactically and semantically legal — to have `#include "externdemo2.c"` inside `externdemo1.c`. – Jonathan Leffler May 07 '13 at 03:26
  • @JonathanLeffler The compiler says the function `display()` is `undefined` if I don't include the second file.Isn't the linker supposed to link to it when I use `extern` in the declaration of that function in the first file `externdemo1.c`?Or linker looks only in default folders? – Rüppell's Vulture May 07 '13 at 03:29
  • @JonathanLeffler So Mr.Leffler, does the linker looks only in select folders?It is clearly not linking to the second file as if I remove the `#include "externdemo2.c"` part,then the compiler says `display()` is undefined even though I have used `extern` before it in its declaration in `externdemo1.c`,the first file. – Rüppell's Vulture May 07 '13 at 03:35
  • Hi, I used vc++ 2010 compiler and got linker error for display() function. correcting the code worked perfectly fine. Not sure which compiler you used. I did not test it on clang or gcc. – Kajal Sinha May 07 '13 at 03:37
  • you can try using the following link to link your files.http://crasseux.com/books/ctutorial/Compiling-multiple-files.html – Kajal Sinha May 07 '13 at 03:40
  • @KajalSinha I am afraid you have simply changed the program to deal with the warnings or errors,but not answered my question!! – Rüppell's Vulture May 07 '13 at 03:42
  • @KajalSinha Why would I define `arr` in the second file?I want it to be in the first file and make it work that way. – Rüppell's Vulture May 07 '13 at 03:43
  • @Rüppell'sVulture: Gimme time...I've updated my answer to address your question. No, the linker is not obliged to spend any time looking for stray object files that might satisfy references; it is expected to link those files and libraries that it is told to link and not add others at its whim. – Jonathan Leffler May 07 '13 at 03:43
  • @JonathanLeffler Last thing.Do you mean we have to mention in the command line's command which files to link to the main file?Even though I have the bad habit of using a GUI (MingW),it would help me to know how things work for referenced objects.Do we have to mention it,something like `gcc -externdemo1.c -externdemo2.o -o result.exe`? – Rüppell's Vulture May 07 '13 at 03:50
0

Using #include as shown will make both as one file only. You can check the intermediate file with flag -E, as in:

gcc -E externdemo1.c
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
nishant pathak
  • 342
  • 1
  • 4
  • 17
  • But the compiler says `display()` is undefined if I don't include the second file.I expect the linker to link to that second file even without including the second file.But it's clearly not doing so.BTW edit your answer.The format is bad.The code is in big bold letters. – Rüppell's Vulture May 07 '13 at 03:33
  • u have to compile both file as: gcc-o output extrademo1.c extrademo2.c and run as ./output – nishant pathak May 09 '13 at 14:03