1

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.

alk
  • 69,737
  • 10
  • 105
  • 255
  • Just use `int number;` in the header files; this is a so-called "tentative definition" in your object files, which will cumulate in a single definition at link time. And yes, number gets initialized with 0 as any global variable. – Ctx Oct 20 '18 at 15:15
  • @Ctx Somehow contradicts the given Answer with your comment. –  Oct 20 '18 at 15:16

2 Answers2

1

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.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • 1
    Well, many toolchains and I think posix allows multiple definitions... – Antti Haapala -- Слава Україні Oct 20 '18 at 15:15
  • So this means that if i declare `int number` in main, there is no need to be declared in `functions.c` as well? –  Oct 20 '18 at 15:15
  • is this same for functions as well or only for variables? –  Oct 20 '18 at 15:15
  • @MichaelB. Yes if you define it explicitly in `functions.c` you will have the same problem with multiple definitions. And yes it's the same for functions too. – Some programmer dude Oct 20 '18 at 15:16
  • Never heard of tentative definitions yet? – Ctx Oct 20 '18 at 15:19
  • So this means that if I use the keyword `extern` for all variables and functions in header files it will be OK. Thank you. –  Oct 20 '18 at 15:20
  • @MichaelB. Functions are `extern` by default, no need to explicitly specify this.You can make them "local" to the translation unit (the .c file) by declaring them `static`. – alk Oct 20 '18 at 15:24
  • @alk I understand. To bad that I can not up vote this Question due the less than 15 rep. –  Oct 20 '18 at 15:26
  • @MichaelB. No, that's ok, since already the first paragraph is wrong. – Ctx Oct 20 '18 at 15:29
  • @alk, there is a sloght difference betwen`extern void f(void);` and `void f(void);`. The first is a declaration, the second is a prototype. – Paul Ogilvie Oct 20 '18 at 15:39
  • @PaulOgilvie The first is only a declaration or it is also a declaration and prototype. I am talking about its presence in Header files. –  Oct 20 '18 at 15:53
0

In addition to Some programmer dude's answer, I use the following construct:

// functions.h
#indef EXTERN
# define EXTERN extern
#endif
EXTERN int number;

// functions.c
#include "functions.h"

// main.c
#define EXTERN
#include "functions.h"

When main compiles, storage will be allocated for number. In all other source files, it will be declared as extern.

Paul Ogilvie
  • 25,048
  • 4
  • 23
  • 41
  • So how can I use a variable in main which is defined in header file, but it will not be seen in other `.c` files? for example if I need `number` to be seen only in `main.c` –  Oct 20 '18 at 15:49
  • Then define it in main: `static int number;` – Paul Ogilvie Oct 21 '18 at 13:04
  • I did already that and I got: `error: static declaration of ‘number’ follows non-static declaration` –  Oct 21 '18 at 13:55
  • define it ONLY in main. Not in the header anymore. – Paul Ogilvie Oct 21 '18 at 14:45