Why aren't my compile guards preventing multiple definition inclusions?
Asked Answered
A

6

73

I have a header file x.h which is included by more than one *.c source files. This header file has some structure variables defined.

I have put multiple inclusion prevention guard at the beginning of the header file as:

#ifndef X_H
#define X_H
...
..
//header file declarations and definitons.


#endif//X_H

On building I get linker errors related to multiple definitions. I understand the problem.

  1. Won't a multiple inclusion prevention guard at the top of header file as I have, prevent multiple inclusions of the header file x.h and thereby avoid multiple definitions of the variables that are there in x.h?

  2. #pragma once does not work on this particular compiler, so what is the solution? Someone had posted this answer to a similar question. It doesn't seem to work for me. How does this solution work?

Addie answered 30/10, 2008 at 9:52 Comment(2)
@Stephen: If you are already editing the question title, please also have a look at the body (and maybe tags, though not here). This avoids duplicate editing (and bumping).Cassy
@Paulo Missed it, I've been trying to watch for it though, thanks for the reminder!Modest
I
99

If the linker is complaining, it means you have definitions rather than just declarations in your header. Here's an example of things that would be wrong.

#ifndef X_H
#define X_H

int myFunc()
{
  return 42; // Wrong! definition in header.
}

int myVar; // Wrong! definition in header.

#endif

You should split this into source and header file like this:

Header:

#ifndef X_H
#define X_H

extern int myFunc();

extern int myVar; 

#endif

C Source:

int myFunc()
{
  return 42; 
}

int myVar; 
Incentive answered 30/10, 2008 at 10:15 Comment(4)
The 'int myVar;' is at most a tentative definition; it usually does not cause trouble. If there was an initializer, it would. Still, I always use an explicit extern as you show in the 'fixed' version.Rodrigues
@Jonathan:Is there such a thing as a "tentative definition" in the C standard?? I think what happens is that multiple definitions like this cause "undefined behaviour", but in many compilers/linkers (gcc...), the behaviour you get is actually what you want!Incentive
would it be possible to have a inlined declaration of a function followed immediately by its definition?Attractant
+1 for correctly differentiating between a definition and a declaration. Some answers to related questions fail to do so, thereby giving technically incorrect information.Timbale
P
28

Header guards are only good for a single compilation unit, i.e., source file. If you happen to include a header file multiple times, perhaps because all headers included from main.c in turn include stdio.h then guards will help.

If you have the definition of a function f in x.h which is included by main.c and util.c, then it is like copying and pasting the definition of f into main.c when creating main.o and doing the same for util.c to create util.o. Then the linker will complain and this happens despite your header guards. Having multiple #include "x.h" statements in main.c is possible of course because of these guards.

Plank answered 6/3, 2012 at 0:24 Comment(2)
I was having this doubt since long time! Your explanation clears it :-)Roofdeck
Helpful explanation.Troublemaker
E
18

Using include guards prevents one compilation unit from including the header twice. E.g. if header B.h includes A.h and B.cpp includes A.h and B.h, everything from A.h would be declared twice in the compilation B.cpp if you weren't using include guards.

Your include guards prevent this from happening, all's fine till now.

But you get multiple definitions at link time, i.e. two compilation units define the same thing, this probably means you got a real definition in your header, use extern for all variables, make sure functions are either inline or are defined in the cpp file.

Ella answered 30/10, 2008 at 10:1 Comment(0)
B
15

If the functions aren't large, you can use "inline" before them and the linker won't complain.

Bag answered 16/7, 2010 at 23:5 Comment(0)
C
2

Using a multiple inclusion guard prevents compiler errors, but you're getting a linker error. Do you have data definitions in the header file that don't use extern?

Casares answered 30/10, 2008 at 9:56 Comment(0)
W
0

Maybe X_H is already defined somewhere else? I just ran into this issue, where Xlib defines X_H in /usr/include/X11/X.h.

To check, you can call gcc -dM -E (if you are using gcc), e.g. in the buildsystem I’m using that works with CC=gcc CFLAGS="-dM -E" make. If the output file contains #define X_H even though you remove it from your file (use Y_H for example), then it is already defined outside your source code.

Womanizer answered 21/9, 2012 at 13:35 Comment(1)
If the include guard was already defined, he would get an error about no definition, rather than multiple definitions, right?Constitutionality

© 2022 - 2024 — McMap. All rights reserved.