Search code examples
cglobal-variablesextern

Define a variable in header file works only when extern keyword is not present?


I am learning at moment C and I really do not understand how header files works and to be sure I have two Questions.

1) Let's take a look at the following program: main.c:

#include <stdio.h>
#include <string.h>
#include "functions.h"


int main( void )
{
    printf( "Num = %d\n", number );
    printNumber();
    return 0;
}

functions.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "functions.h"

void printNumber( void )
{
    printf("Number = %d\n", number );
}

functions.h:

#ifndef FUNCTIONS
#define FUNCTIONS

int number;
extern void printNumber( void );

#endif // FUNCTIONS

The way the program is in the Header file there is no extern keyword involved so there seems to be reference to number and the program Outputs:

Num = 0
Number = 0

The first Question is, does number get initialized (is number global variable or similar if number is present only in the header file) and is this a legal code/program?

Second scenario, let's take a look at the following code main.c:

#include <stdio.h>
#include <string.h>
#include "functions.h"

int main( void )
{
    printf( "Num = %d\n", number );
    printNumber();
    return 0;
}

functions.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "functions.h"

void printNumber( void )
{
    printf("Number = %d\n", number );
}

functions.h:

#ifndef FUNCTIONS
#define FUNCTIONS

extern int number;
extern void printNumber( void );

#endif // FUNCTIONS

Here the program will not compile due the

`undefined reference to number`

Which force me to declare number in main:

#include <stdio.h>
#include <string.h>
#include "functions.h"

int number;

int main( void )
{
    printf( "Num = %d\n", number );
    printNumber();
    return 0;
}

Which is the Right way and why? Last thing, why does exactly not apply to void printNumber( void ) as well. I see that it is working with or without the extern keyword.


Solution

  • For the first version, in your header file, you define the variable number. That means every translation unit that includes the header file will have a definition of the variable. That's not allowed, you can only have a single definition spread over all translation units.

    The solution to that problem is to declare the variable in the header file instead:

    extern int number;
    

    The use of the keyword extern marks this as a declaration instead of a definition, the compiler will know that the variable is defined somewhere else.

    Then you of course need to define it somewhere. In one single source file put the definition:

    int number;
    

    I.e. exactly what you do in your last variant.