Multiple definition of a variable in a multi-file sketch

Trying to link a sketch that is made up of four files.

The two error msg’s are: " multiple definition of var_1' " and " multiple definition of var_2’ "

Here is the code for all four files:

/* FILE: multi_file.ino */

#include "multi_file.h"

void setup() { }

void loop() {
  fnc_1();
  fnc_2();
}
/* FILE: multi_file.h */

#ifndef multi_file_h
#define multi_file_h

#include "Arduino.h"

byte var_1 = 0;
void fnc_1( void );
byte var_2 = 0;
void fnc_2( void );

#endif
/* FILE: fnc_1.cpp */

#include "multi_file.h"

void fnc_1( void ) {
  var_1 = 1;
}
/* FILE: fnc_2.cpp */

#include "multi_file.h"

void fnc_2( void ) {
  var_2 = 1;
}

Is there a question?

DECLARE the variables as ‘extern’ in the .h file.
DEFINE them in one (and only one) of the .cpp files.

Thanks, gfvalvo.

I tried your suggestion and prepended "extern" to the variable definitions in multi_file.h. That did not remedy the problem. Here is the code for the updated file.

/* FILE: multi_file.h */

#ifndef multi_file_h
#define multi_file_h

#include "Arduino.h"

extern byte var_1 = 0;
void fnc_1( void );
extern byte var_2 = 0;
void fnc_2( void );

#endif
extern byte var_1;
void fnc_1( void );
extern byte var_2;
void fnc_2( void );

Thanks AWOL,

I removed the initial values from the header file, as you suggested. That did not remedy.

Here is the code for the updated header file:

/* FILE: multi_file.h */

#ifndef multi_file_h
#define multi_file_h

#include "Arduino.h"

extern byte var_1;
void fnc_1( void );
extern byte var_2;
void fnc_2( void );

#endif

Show where you defined the variables.

Thanks gfvalvo,

I don't understand what you are asking by "show where you defined the variables." Can you explain the difference between defining a variable and declaring a variable? I presented all of the code in my first post.

Thanks for your forbearance. It's been awhile since I coded, and am rusty.

I presented all of the code in my first post.

...and you've changed it since then, and we can't see your screen.

sthudium:
Can you explain the difference between defining a variable and declaring a variable?

https://www.cprogramming.com/declare_vs_define.html

Thanks, gfvalvo, I will now read your provided link.

I sincerely apologize, AWOL, if I was difficult. Here is the latest version of my code:

/* FILE: multi_file.ino */

#include "multi_file.h"

void setup() {
}

void loop() {
  fnc_1();
  fnc_2();
}
/* FILE: multi_file.h */

#ifndef multi_file_h
#define multi_file_h

#include "Arduino.h"

extern byte var_1;
void fnc_1( void );
extern byte var_2;
void fnc_2( void );

#endif
/* FILE: fnc_1.cpp */

#include "multi_file.h"

void fnc_1( void ) {
  var_1 = 1;
}
/* FILE: fnc_2.cpp */

#include "multi_file.h"

void fnc_2( void ) {
  var_2 = 1;
}

Hi gfvalvo,

I read your link. It now seems to me that I should not have put the extern keywords in the header file. Instead, I could have put an "extern byte var_1;" above fnc_1 and likewise for fnc_2. However, that would not be necessary, it seems, if those functions are in files that include the header file (#include "multi_file.h") at the top.

No, leave the extern declaration in the .h file. #include the .h in both .cpp files. The problem is that you're defining the variables as local in the .cpp files. Make them globals.

Also, see here: Multiple variable definition error when compiling with .h and .cpp file tabs - #6 by gfvalvo - Programming Questions - Arduino Forum

Thanks gfvalvo,

I got it to work by declaring and defining the global variables in the same cpp file, and using the extern keyword in the other files that reference a global variable.

Apparently my original problem occurred because I declared and defined the global variables in the header file, which was included in multiple cpp files. That is why I got the multiple definition errors.

Here is the final code (I added a define_global_var.cpp file to the original four files):

/* FILE: multi_file.ino */

#include "multi_file.h"

void setup() {
}

void loop() {
  fnc_1();
  fnc_2();
}
/* FILE: multi_file.h */

#ifndef multi_file_h
#define multi_file_h

#include "Arduino.h"

extern byte var_1;
extern byte var_2;

void fnc_1( void );
void fnc_2( void );

#endif
/* FILE: define_global_var.cpp 
 *
 * Declares AND define global variables, which is normally done in the ino file. 
 */

#include "Arduino.h"

byte var_1 = 0;
byte var_2 = 0;
/* FILE: fnc_1.cpp */

#include "multi_file.h"

void fnc_1( void ) {
  var_1 = 1;
}
/* FILE: fnc_2.cpp */

#include "multi_file.h"

void fnc_2( void ) {
  var_2 = 1;
}

See reply #2

However, I don't understand why the #ifndef-#endif construct in the header file did not prevent multiple variable definitions when that header file is included in multiple files.

Isn't that the purpose of the #ifndef-#endif construct?

sthudium:
However, I don't understand why the #ifndef-#endif construct in the header file did not prevent multiple variable definitions when that header file is included in multiple files.

So you have to understand how the preprocessor builds Translation Units.

A translation unit is the basic unit of compilation in C++. It consists of the contents of a single source file, plus the contents of any header files directly or indirectly included by it, minus those lines that were ignored using conditional preprocessing statements.

By defining and declaring the variable in your header, every translation unit will then have its own copy of that variable... you #include the header twice (once in your .ino and once in your .cpp file) so when the compilation comes together, you then have two like-named variables that cannot be resolved during the compilation (literally "Putting Together") of the Translation units.

The #include guards simply prevent the entire header from being copied into a Translation Unit more than once.

You're so right, AWOL. gfvolvo did answer my original problem in Reply #2. I guess I was just too dense to understand it at the time. Ugh. Sorry for spinning everyone's wheels.

Thanks, BullDogLowell,

You corrected my misunderstanding of the #ifndef-#endif construct. That only prevents multiple use of the header file by the same source file. I incorrectly thought it prevented multiple use by the entire source code suite.