I want do define a variable in the header and be able to use it in multiple files.
e.g. have variable a
defined somewhere and be able to use/change it in both p1.cpp and p2.cpp
Here is an example with 3 simple files of what I'm trying to do.
// vars.hpp
#ifndef VARS_HPP
#define VARS_HPP
int a = 1;
float b = 2.2;
void double_vars();
#endif
// vars.cpp
#include "vars.hpp"
void double_vars () {
a *= 2;
b *= 2;
}
// vars_main.cpp
#include <cstdio>
#include "vars.hpp"
int main () {
printf("a: %d; b: %f\n", a, b);
double_vars();
printf("a: %d; b: %f\n", a, b);
}
now, compiling the above with:
g++ -Wall -W -g vars.cpp vars_main.cpp -o vars && ./vars
gives me the following errors:
/tmp/ccTPXrSe.o:(.data+0x0): multiple definition of `a'
/tmp/ccnc1vof.o:(.data+0x0): first defined here
/tmp/ccTPXrSe.o:(.data+0x4): multiple definition of `b'
/tmp/ccnc1vof.o:(.data+0x4): first defined here
can someone explain to me why this happens? I have guards in the header file so as far as I understand it should only be included once so there should not be multiple declarations
In the header file, write this:
This will declare the variables.
In one of the CPP files, write this:
This will define the variables. It does not matter in which CPP file you put the definitions, as long as the variables are defined exactly once.
Collin already described the problem and the solution, but I want to emphasize just how bad a style this is.
As you've found out even from this simple exercise, using globals in this manner is often a Bad Thing. Aside from the compiler issues you've already found, sharing state between functions using globals causes the following problems:
it makes the function itself harder to reuse in other programs, because the function is expecting the presence of those symbols;
changes to one function may cause problems in other functions that share that state (i.e., the changes are not localized to the function);
code becomes harder to debug, since anyone can modify
a
andb
at any time.Ideally, functions should communicate exclusively through parameters, return values, and exceptions (where applicable); there are times where sharing state is the right answer, but those are relatively few and far between.
Since you're obviously using a C++ compiler, I'm going to do this the C++ way, using references instead of pointers. I'm also going to use C++
iostream
routines instead ofcstdio
(write either C or C++; trying to mix the two only leads to heartburn).vars.hpp:
vars.cpp:
main.cpp:
Since
x
andy
were declared as reference types (using the&
), writing to the expressionsx
andy
indouble_vars
is equivalent to writing toa
andb
inmain
.The C way of doing this would be with pointers instead of references:
vars.h:
vars.c:
main.c:
In this case, we're using pointers instead of references, so we need to pass the result of the expressions
&a
and&b
todouble_vars
; within the function, writing to the expressions*x
and*y
is the same as writing toa
andb
inmain
.First off, don't do this. Global mutable state is usually a bad thing.
The problem is that once the linker finishes combining the files in your include statments, it has seen this twice, once in main.cpp and once in vars_main.cpp:
If you only put this in the header file, it shows up in multiple translation units, once for each
cpp
file that includes your header. It's impossible for the compiler to know which a and b you're talking about.The way to fix this is to declare them
extern
in the header:This tells the compiler that a and b are defined somewhere, not necessarily in this part of the code.
Then, in one of your cpp files you would define them:
That way, there's one well-defined place for the storage for
a
andb
to live, and the compiler can connect the dots properly.