Search code examples
cextern

Defining extern variables in C application with multiple files


Here is the specific problem I am facing.

I have an application with files such as Names.c Names.h Names_e.c Names_e.h Names_f.c Names_f.h, among other files. Names.c uses strings declared and defined in Names_e (.h and .c) to define its own array variables. Similarly, the second element for those arrays comes from strings defined in Names_f (.h and .c).

Now I defined all elements in Names_e.h and Names_f.h as 'extern' variables. Why does my application throw an "Unresolved symbol"error when I only include the header files Names_e.h and Names_f.h in Names.c?? I had to include the respective .c files i.e Names_e.c and Names_f.c to remove the error.

I thought 'extern' keyword tells the compiler that the definition is somewhere else in the code. So should nt including the header files be enough??

Will appreciate any input. Thanks in advance.

Names.c

#include Names_e.h
#include Names_f.h
const DISPSTRING * const * s_MenuName[2] =            {s_MenuName_e,
                                                      s_MenuName_f};

Names_e.c

const DISPSTRING M1                 = {0,"1."};
const DISPSTRING M2                 = {0,"2."};
const DISPSTRING M3                 = {0,"3."};
const DISPSTRING * const s_MenuName_e[3]    =  {&M1,&M2,&M3}; 

Names_f.c

const DISPSTRING M1_f                   = {0,"1."};
const DISPSTRING M2_f                   = {0,"2."};
const DISPSTRING M3_f                   = {0,"3."};
const DISPSTRING * const s_MenuName_e[3]    =  {&M1_f,&M2_f,&M3_f};

In Names.h

#include Names_e.h
#include Names_f.h

extern const DISPSTRING * const * s_MenuName[2];

Names_e.h

extern const DISPSTRING * const s_MenuName_e[3];

Names_f.h

extern const DISPSTRING * const s_MenuName_f[3];

Answer-> It was not the code but the makefile that needed a change (addition of the new files to the list of source files and header files plus the addition of respective object file locations). I mistakenly thought the IDE does this automatically! Thank you all for the solutions posted.


Solution

  • Now I defined all elements in Names_e.h and Names_f.h as 'extern' variables. Why does my application throw an "Unresolved symbol"error when I only include the header files Names_e.h and Names_f.h in Names.c?

    [...]

    I thought 'extern' keyword tells the compiler that the definition is somewhere else in the code. So should nt including the header files be enough??

    The extern keyword does express that the object or function so declared is defined elsewhere. Therefore, if you refer to that object in your code, the "elsewhere" needs also to be linked into (or compiled into) your code.

    I had to include the respective .c files i.e Names_e.c and Names_f.c to remove the error.

    You should not need to do that, nor indeed should you do it. But if the application in question is comprised of all these files, then to build an executable you do need to compile all those files and link them together. How exactly you do that depends somewhat on your toolchain, but traditionally, there are two general approaches:

    1. Compile all the sources at once, by specifying the names of all the .c files in your compilation command. (This is very different from #includeing one .c file in another.)

    2. Compile each source individually to an intermediate "object file" form, and then link them all together in a separate step.

    You cannot mix and match. That is, if you intend to use the second alternative, then you must make sure that you compile to object file form. That typically requires additional compiler flags that you would not use for option (1).

    Taking gcc as an example, option (1) might look like this:

    gcc -o myprog Names.c Names_e.c Names_f.c other.c
    

    whereas option (2) might look like this:

    gcc -c Names.c
    gcc -c Names_e.c
    gcc -c Names_f.c
    gcc -c other.c
    gcc -o myprog Names.o Names_e.o Names_f.o other.o
    

    But if you try to do gcc Names.c then it will attempt to build an executable program from Names.c alone, and that will fail because of (at least) the unrealized external definitions you described.