I'm writing a C++ program where each file has it's own set of global variable declarations. Most of these files make use of global variables that were defined in the other files using extern.
Here's an example similar to my program:
Main.cpp
#include "stdafx.h"
#include <iostream>
#include "Other_File.cpp"
int var1;
int var2;
int main()
{
var1 = 1;
var2 = 2;
otherFunction();
var4 = 4; // From Other_File.cpp
std::cout << var1 << " " << var2 << " " << var3 << " " << var4 << std::endl;
return(0);
}
Other_File.cpp
extern int var1;
extern int var2;
int var3;
int var4;
void otherFunction()
{
var3 = var1 + var2;
var4 = 0;
}
When I build this code in Visual Studio (Windows), everything runs fine and the output is correct. But when I attempt to build using g++ on Linux I receive the following error:
g++ -o Testing Testing.o Other_File.o Other_File.o:(.bss+0x0):
multiple definition of var3' Testing.o:(.bss+0x0): first defined here
Other_File.o:(.bss+0x4): multiple definition of
var4'
Testing.o:(.bss+0x4): first defined here Other_File.o: In function
otherFunction()': Other_File.cpp:(.text+0x0): multiple definition of
otherFunction()' Testing.o:Testing.cpp:(.text+0x0): first defined
here collect2: ld returned 1 exit status make: *** [Testing] Error 1
Is this because I'm "including" the other file in my main file?
If not what's the issue with my code?
Edit: This is the content of my Makefile for g++:
Testing: Testing.o Other_File.o
g++ -o Testing Testing.o Other_File.o
Testing.o: Testing.cpp
g++ -c -std=c++0x Testing.cpp
Other_File.o: Other_File.cpp
g++ -c -std=c++0x Other_File.cpp
clean:
rm *.o Calculator
Don't #include
a source file into another source file. There times and places when that is okay, but only in like less than 0.001% of all programs is that needed.
What you should do is create a header file which contains declarations of the things needed in both source files.
Then your code would look like this:
main.cpp
source file
#include "stdafx.h"
#include <iostream>
#include "Other_File.h" // Note inclusion of header file here
int var1;
int var2;
int main()
{
var1 = 1;
var2 = 2;
otherFunction();
var4 = 4; // From Other_File.cpp
std::cout << var1 << " " << var2 << " " << var3 << " " << var4 << std::endl;
}
other_file.cpp
source file, just like you have it now
other_file.h
header file, a new file
#pragma once
// Declare the variables, so the compiler knows they exist somewhere
extern int var3;
extern int var4;
// Forward declaration of the function prototype
void otherFunction();
Both source files would then be compiled separately and linked together to form the final executable. This linking step is where your build fails. It will notice that the variables defined in other_source.cpp
are defined in the object file created from that source file, but since you include it into the main.cpp
source file then the object file created from that source file as well.
This is why you need to learn about translation units, which is what the compiler actually see. A C++ source file goes through many phases of translation, each one doing its own special part. Roughly a translation unit is a single source file with all the headers included.
This is also a good reason to learn what the preprocessor #include
directive does. It basically inserts the included file, as is, into the source file being preprocessed. Where the #include
directive was, after preprocessing it will be the contents of the included file, and that is what the compiler will see.
An include effectively pastes the included file into the including file before the compiler starts working, so what this looks like to the compiler is:
#include "stdafx.h"
#include <iostream>
// #include "Other_File.cpp" sub in other file here
extern int var1;
extern int var2;
int var3;
int var4;
void otherFunction()
{
var3 = var1 + var2;
var4 = 0;
}
int var1;
int var2;
int main()
{
var1 = 1;
var2 = 2;
otherFunction();
var4 = 4; // From Other_File.cpp
std::cout << var1 << " " << var2 << " " << var3 << " " << var4 << std::endl;
return(0);
}
By itself this isn't a problem. It's funny looking, but it's not a problem. There are no duplicated variables.
extern int var1;
tells the compiler that somewhere else the there exists var1
. It will be found and linked later. Carry on. The linker will complain if you lied. In this case, there it is about 10 lines down.
The problem comes when Other_File.cpp is compiled and linked with Main.cpp. The linker finds a full definition of var3
and var4
in both Main.o and Other_File.o
You can exclude Other_File.cpp from the build, likely what Visual Studio did for you, and all will be good except for a serious violation of convention: Never include a .cpp file.
Why? Because cpp files, by convention, define stuff and make them real. You can botch a .h file just as badly by defining a variable or function in the header. eg:
#ifndef BADHEADER_H_
#define BADHEADER_H_
int fubar; // don't do this
/* do this instead:
extern int fubar;
and place int fubar; into the most logical cpp file
*/
#endif /* BADHEADER_H_ */
Everyone who includes badheader.h now has a variable named fubar
whether they want it or not and when the linker comes along to assemble the program, which fubar
is the real fubar
? All of them. Whoops. All the poor linker can do is spit out an error and wait for you to fix the ambiguity.
At the end of the day you can #include
anything. It won't compile, but you could include a Word doc. You can even perform little tricks like
int array[] =
{
#include "filtercoefs.h"
};
where array.h is simply
1,2,3,4,5
Useful when you have something like Matlab spitting out filter coefficients, but prefer sticking to the convention to prevent confusion among your fellow coders.
Anyway, C++ lets you do all sorts of stuff. Most of them you better think over a few times before doing them.