8

For some reason, I'm getting multiple declarations of content within my header file even though I'm using header guards. My example code is below:

main.c:

#include "thing.h"

int main(){
    printf("%d", increment());

    return 0;
}

thing.c:

#include "thing.h"

int increment(){
    return something++;
}

thing.h:

#ifndef THING_H_
#define THING_H_

#include <stdio.h>

int something = 0;

int increment();

#endif

When I attempt to compile this, GCC says that I have multiple definitions of the something variable. ifndef should make sure that this doesn't happen, so I'm confused why it is.

user1007968
  • 83
  • 1
  • 3
  • 2
    The *compiler* error "multiple *declarations*" is not the same as the *linker* error "multiple *definitions*". You have mentioned both in your question (when in fact the only problem is the latter); understanding the difference is key to understanding what is going wrong. The header guards prevent multiple *declarations*, not multiple *definitions*. – Clifford Oct 28 '11 at 07:32
  • @Clifford sorry, I should have mentioned I was getting a linker error. – user1007968 Oct 28 '11 at 12:25
  • Also, in C `int increment();` is not a prototype but declares a function with unspecified number of parameters. Use `int increment(void);` for that. – Jens Gustedt Oct 28 '11 at 13:50

6 Answers6

13

The include guards are functioning correctly and are not the source of the problem.

What happens is that every compilation unit that includes thing.h gets its own int something = 0, so the linker complains about multiple definitions.

Here is how you fix this:

thing.c:

#include "thing.h"

int something = 0;

int increment(){
    return something++;
}

thing.h:

#ifndef THING_H_
#define THING_H_

#include <stdio.h>

extern int something;

int increment();

#endif

This way, only thing.c will have an instance of something, and main.c will refer to it.

NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • 2
    You might as well add that even if there would be no multiple definition errors,each TU will have its own copy of the variable and it would not achieve the purpose which is sharing the same variable across all the source files. – Alok Save Oct 28 '11 at 07:56
4

You have one definition in each translation unit (one in main.c, and one in thing.c). The header guards stop the header from being included more than once in a single translation unit.

You need to declare something in the header file, and only define it in thing.c, just like the function:

thing.c:

#include "thing.h"

int something = 0;

int increment(void)
{
    return something++;
}

thing.h:

#ifndef THING_H_
#define THING_H_

#include <stdio.h>

extern int something;

int increment(void);

#endif
caf
  • 233,326
  • 40
  • 323
  • 462
4

The header guards will stop the file from being compiled more than once in the same compilation unit (file). You are including it in main.c and thing.c, so it will be compiled once in each, leading to the variable something being declared once in each unit, or twice in total.

Brian Hooper
  • 21,544
  • 24
  • 88
  • 139
1

The variable something should be defined in a .c file, not in a header file.

Only structures, macros and type declarations for variables and function prototypes should be in header files. In your example, you can declare the type of something as extern int something in the header file. But the definition of the variable itself should be in a .c file.

With what you have done, the variable something will be defined in each .c file that includes thing.h and you get a "something defined multiple times" error message when GCC tries to link everything together.

Simon C
  • 1,977
  • 11
  • 14
  • Your first statement is incorrect.The variable should be *declared* with *extern* keyword in the header file and *defined* in one and only source file. – Alok Save Oct 28 '11 at 07:51
1

try to avoid defining variables globally. use functions like increment() to modify and read its value instead. that way you can keep the variable static in the thing.c file, and you know for sure that only functions from that file will modify the value.

Chris
  • 908
  • 6
  • 11
0

what ifndef is guarding is one .h included in a .c more than once. For instance

thing. h

#ifndef
#define

int something = 0;
#endif

thing2.h

#include "thing.h"

main.c

#include "thing.h"
#include "thing2.h"
int main()
{
  printf("%d", something);
  return 0;
}

if I leave ifndef out then GCC will complain

 In file included from thing2.h:1:0,
             from main.c:2:
thing.h:3:5: error: redefinition of ‘something’
thing.h:3:5: note: previous definition of ‘something’ was here
manuzhang
  • 2,995
  • 4
  • 36
  • 67
  • While your explanation is correct,OP's problem is not that,the inclusion guards are definitely *in-place*. – Alok Save Oct 28 '11 at 07:54
  • I can agree with @manuzhang given what I've read here. I'll leave them in for form's sake, but I don't plan on including a header multiple times within one compilation unit. :) – user1007968 Oct 28 '11 at 12:42
  • well, with larger projects you have to do so and that's where `ifndef` comes in – manuzhang Oct 28 '11 at 14:43