0

I have a project with multiple header files and .cpp files. All of the header files have include guards.

There is a file called Constants.h where I define some constants. Some of these with defines, some as constant variables.

There are more header-.cpp-file pairs with code in them. One of these does contain a class, the others don't.

When I include my files into my main file (an arduino sketch), I get a lot of linker errors, claiming there are multiple definitions of some variables.

I read that this mainly occurs when you include .c or .cpp files, which I don't do. All the .cpp files only include their appropriate header files.

I did manage to find multiple solution proposals:

1) inline:

With functions, inline can be used to get rid of this problem. However, this is not possible with variables.

2) anonymous namespace:

This is one of the solutions I used. I put anonymous namespaces around all the problematic definitions I had. It did work, however I do not understand why this works. Could anyone help me understand it?

3) moving definitions into .cpp files:

This is another approach I used sometimes, but it wasn't always possible since I needed some of my definitions in other code, not belonging to this header file or its code (which I do admit is bad design).

Could anyone explain to me where exactly the problem lies and why these approaches work?

Lithimlin
  • 542
  • 1
  • 6
  • 24

3 Answers3

3

Some of these with defines, some as constant variables.

In C const does not imply the same thing as it does in C++. If you have this:

const int foo = 3;

In a header, then any C++ translation unit that includes the header will have a static variable named foo (the const at namespace scope implies internal linkage). Moreover, foo can even be considered a constant expression by many C++ constructs.

Such is not the case in C. There foo is an object at file scope with external linkage. So you will have multiple definitions from C translation units.

A quick fix would be to alter the definitions into something like this:

static const int foo = 3;

This is redundant in C++ but required in C.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • That really cleared up a lot. Adding `static` to the problematic definitions did the trick. I'm just surprised that I never stumbled across this before... – Lithimlin Feb 04 '19 at 14:35
  • @Lithimlin - Normally C headers will not have objects like that. And C++ headers will have other things that are way more likely to not be valid C. – StoryTeller - Unslander Monica Feb 04 '19 at 14:36
2

In addition to Story Teller's excellent explanation, to define global variables, use the following:

// module.h
#include "glo.h"

// glo.h
#ifndef EXTERN
# define EXTERN extern
#endif
EXTERN int myvar;

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

In main.c all variables will be declared (i.e. space is allocated for them), in all other c files that include glo.h, all variables will be known.

Paul Ogilvie
  • 25,048
  • 4
  • 23
  • 41
0

You shouldn't declare any object in header files, this should be moved to c\c++ files.

In header you may:

  • declare types such as: classes, structs, typedefs etc.
  • put forward declarations of (not classes) functions
  • put inline (or in classes) functions (+ body)
  • you may add extern declaration.
  • you may put your macros.

a static declaration may declare things multiple times, therefore it is not recommended.

SHR
  • 7,940
  • 9
  • 38
  • 57