27

I have a C program with several c and h files. I decided to make one part of the program 'header-only' so I moved the code from c to h. Now I'm getting multiples definition problems and I have no idea why. e.g.:

main.c includes utils.h
vector.c includes utils.h

I moved everything in utils.c to utils.h (and of course removed utils.c from the project). utils.h starts with

#ifndef UTILS_H_
#define UTILS_H_

// and end with:
#endif

To be sure my guard was unique I tried changing it (e.g.: UTILS718171_H_) but it doesn't work.

Still, the compiler complains:

/tmp/ccOE6i1l.o: In function `compare_int':
ivector.c:(.text+0x0): multiple definition of `compare_int'
/tmp/ccwjCVGi.o:main.c:(.text+0x660): first defined here
/tmp/ccOE6i1l.o: In function `compare_int2':
ivector.c:(.text+0x20): multiple definition of `compare_int2'
/tmp/ccwjCVGi.o:main.c:(.text+0x6e0): first defined here
/tmp/ccOE6i1l.o: In function `matrix_alloc':
ivector.c:(.text+0x40): multiple definition of `matrix_alloc'
/tmp/ccwjCVGi.o:main.c:(.text+0x0): first defined here
...

The problem might be something like: all c files are compiled and get their own version of the code and then at linkage it causes problem, but I have honestly no idea how to solve this problem.

manlio
  • 18,345
  • 14
  • 76
  • 126
Suugaku
  • 2,667
  • 5
  • 31
  • 33
  • try to post utils.h. Remember to put only prototypes or constants inside utils.h – Heisenbug Nov 20 '11 at 13:53
  • question [2174657](http://stackoverflow.com/questions/2174657/when-are-header-only-libraries-acceptable) has some info about when/how to use header-only libraries. – don bright Oct 28 '12 at 00:42

4 Answers4

39

If you define your variables inside your header file and include the header in several c files, you are bound to get multiple definitions error because you break the One definition rule(ODR), which states that there should be only one definition in one Translation Unit(header files + source file).

Solution is:
You should define the entities you get Multiple definition errors for only once.
For Functions:
Declare the function prototypes in header file(which you include in other source files) and define the function in one and only one source file.
For Global variables:
You declare the variable extern in header file(which you include in other source files) and then define the variable in one and only one source file.

Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • Why am I able to define a member function in a class header? I know that implies that the function will be inlined, but is that the only reason? – Brian Schlenker Feb 28 '14 at 15:05
  • 3
    Although this answer was accepted, it is not the right answer to this question because it misses the entire point: the OP wishes to use a header-only file, with all declarations and definitions in the same file. There are legitimate reasons why this may be necessary in the Arduino environment, even without the Arduino IDE. This answer merely states that you should NOT use header-only files. There are three ways to get around the multiple definition problem, each with different implications and costs. IMO the applicable solution here would be to declare any non-member functions as inline. – Craig.Feied Aug 21 '17 at 04:57
  • 1
    why `ifndef` does not work to avoid multiple definitions of the variables? – rsonx Feb 14 '21 at 08:27
  • 1
    @rsonx because the header gets included once, but by multiple source files, each building its own object file. each one includes the header only once, but there is more then one object file. the multiple definitions only come to light when trying to link them together. – xaedes Jun 24 '21 at 14:32
13

You are missing the point of #ifndef _FOO_H / #define _FOO_H / #endif construct. That only protects against multiple inclusions in ONE file. For example they protect against this:

foo.h:

  #ifndef _FOO_H 
  #define _FOO_H

  /* some C stuff here */

  #endif /* _FOO_H */

foo.c:

   #include <foo.h>
   #include <bar.h>
   ...

bar.h:

   #include <foo.h>
   ...

note that foo.c and bar.h both include foo.h; here the #ifdef _FOO_H / #define _FOO_H / #endif protects against that double inclusion in foo.c ( the foo.h included in bar.h doesn't redefine stuff )

Now the next part.

Why would you move function implementation from utils.c to utils.h? Also why did you decide to make it "header-only" ?

You can, depending on whether your compiler supports static inline functions do this; but even then it's NOT recommended, as more than likely, it will make your program unnecessarily bloated because chances are your util functions are quite complex and cannot be inlined anyways.

So change it back to utils.c and utils.h construct that you had before which, i presume, WAS working and enjoy the software.

Jeff Kelley
  • 19,021
  • 6
  • 70
  • 80
Ahmed Masud
  • 21,655
  • 3
  • 33
  • 58
6

If you indend for the utils.h functions to be "copied" into each place where it is used, just use static functions in the header. (static inline in C99)

u0b34a0f6ae
  • 48,117
  • 14
  • 92
  • 101
5

You're violating the One-Definition-Rule. Each function must be defined precisely once, while you end up defining it in each translation unit.

You simply cannot do something like this:

// header.h
void foo() { }

// file1.c
#include "header.h"

// file2.c
#include "header.h"

The only real solution is to declare void foo(); in the header and define it once only (usually in a dedicated foo.c). The same goes for global variables, which should be declared as extern in the header and defined in the source file.

Include guards have nothing to do with this. They only serve to prevent recursive self-inclusion or redundant multiple inclusion within one translation unit.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084