Main questions
Basically, because you've included the source of externdemo2.c
in the file externdemo1.c
.
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.
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]