0

I have a header file that contains an array of int

primes.h

#ifndef P_H
#define P_H
#include <inttypes.h>

uint64_t primes[] = {
    7,
    11,
};
#endif

in lib.h file: #include "primes.h"

lib.c includes lib.h

in main.c file: #include "lib.h"

Then it causes error: duplicate symbol '_primes' in:

But if i move #include "primes.h" into lib.c, it works fine. Why putting include in source and header can make the difference?

TomSawyer
  • 3,711
  • 6
  • 44
  • 79

2 Answers2

2

You are defining a variable in the h-file. This means that you can only include that h-file in one compilation unit, i.e. in one c-file. So when you include it in lib.h and in case lib.h is included in multiple c-files, your in trouble, i.e. multiple compilation units will define the array variable primes. That won't work.

Rule: Don't define variables in h-files. Always do it in c-files.

(note: there may be exceptions but this is the golden rule - stick to it unless you have a real good reason for putting variables in h-files)

See this answer for a how-to description: https://stackoverflow.com/a/1433387/4386427

Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
  • Thank for the compilation unit, i know nothing about it. So is that wrong to do include `primes.h` in source file? I don't wanna use `extern` since i need to create `primes.c` to define variable in it. – TomSawyer Apr 30 '20 at 06:39
  • @TomSawyer When a program is made from several c-files, each of these c-files are a "compilation unit". They are compiled one-by-one and later linked together to form the whole program. I don't understand why you are saying "I don't wanna use extern ..." ? That's the way to do it! Define the variable in a c-file and put the extern declaration in the h-file. – Support Ukraine Apr 30 '20 at 06:47
2

When you include a file, the include is replaced with the file contents (and this continues until there are no more includes).

  • If main.c and lib.c both include lib.h, then they both have separate copies of lib.h compiled in.
  • If lib.h includes primes.h, then they both have their own separate copies of primes.h compiled in.
  • If primes.h has an array defined, then they both have a copy of that array.
  • And if they both have anything with the same name defined in both files, you get a duplicate definition error.

The best way to fix this is to only have 1 definition of the primes array with all of its values in a source file (e.g. lib.c), and you need to use the extern keyword in primes.h with no values to declare that one of your files contains the actual array (you can leave the size unspecified in this case). Note that this use of the extern keyword is a sort of promise to the compiler that there is some file containing the actual array, and that's why you still need the actual array in a source file:

// primes.h
extern uint64_t primes[];

// lib.c
#include "primes.h"
uint64_t primes[] = {
    7,
    11,
};

// main.c
#include "primes.h"
MemReflect
  • 551
  • 2
  • 10