If I declare a global variable in a header file and include it in two .cpp files, the linker gives an error saying the symbol is multiply defined.
My question is, why does this happen for only certain types of object (eg. int) and not others (eg. enum)?
The test code I used is given below:
test.h
#ifndef TEST_HEADER
#define TEST_HEADER
namespace test
{
int i_Test1 = -1;
int i_Test2 = -1;
};
#endif // TEST_HEADER
class1.h
#ifndef CLASS_1_HEADER
#define CLASS_1_HEADER
class class1
{
public:
void count();
};
#endif //CLASS_1_HEADER
class1.cpp
#include <iostream>
#include "class1.h"
#include "test.h"
void class1::count()
{
std::cout << test::i_Test1 << std::endl;
}
class2.h
#ifndef CLASS_2_HEADER
#define CLASS_2_HEADER
class class2
{
public:
void count();
};
#endif //CLASS_2_HEADER
class2.cpp
#include "class2.h"
#include <iostream>
#include "test.h"
void class2::count()
{
std::cout << test::i_Test2 << std::endl;
}
main.cpp
#include "class1.h"
#include "class2.h"
int main(int argc, char** argv)
{
class1 c1;
class2 c2;
c1.count();
c2.count();
return -1;
}
Building this code with:
g++ main.cpp class1.cpp class2.cpp -o a
produces the following output:
ld: fatal: symbol test::i_Test1' is
multiply-defined:
(file /var/tmp//ccwWLyrM.o type=OBJT; file /var/tmp//ccOemftz.o
type=OBJT); ld: fatal: symbol
test::i_Test2' is multiply-defined:
(file /var/tmp//ccwWLyrM.o type=OBJT; file /var/tmp//ccOemftz.o
type=OBJT); ld: fatal: File processing
errors. No output written to a
collect2: ld returned 1 exit status
If I change the test.h file as given below:
test.h (with enum)
#ifndef TEST_HEADER
#define TEST_HEADER
namespace test
{
enum val
{
i_Test1 = 5,
i_Test2
};
//int i_Test1 = -1;
//int i_Test2 = -1;
};
#endif // TEST_HEADER
I don't get the "multiply defined" error and the program gives the desired output:
5
6
That's because enumerations are not objects - they are types. Class types (class,struct,union) and enumerations can be defined multiple times throughout the program, provided all definitions satisfy some restrictions (summed up by the so-called One Definition Rule (ODR)). The two most important ones are
All definitions have the same token sequence (textual identical)
Names used must have the same meaning (resolve to the same things) in all definitions. (this is a requirement on the context of the definition)
Your enumeration definition satisfies all conditions of the ODR. Therefor, that is valid and no reason for the linker / compiler to moan (actually, for a violation of the ODR the compiler is not required to issue a message either - most of it falls under the so-called no diagnostic required rule, some violations also result in undefined behavior).
However, for every non-inline function and object, these must be only defined one time. Multiply defining those result in spurious errors, like in your case. To solve it, put only a declaration into the header file (using "extern" without an initializer) and put one definition into one of those .cpp files (omitting the "extern" then, or putting an initializer. If it is a const object, you still need the "extern", since per default const variables have internal linkage, and the symbol would not be exported otherwise).
Related
I have been trying to use extern in order to use variable that is previously defined.
I have not used extern before and now I need to use it in order to define variable just once and use them across multiple files
I have written minimized version of code for this question. I have four files
lib.h
#ifndef LIB_H
#define LIB_H
#include <iostream>
namespace lib {
extern bool initialized;
bool initialized = false;
static void isInit(char* parent) {
std::cout << "Library for [" << parent << "] initialized? " << (::lib::initialized ? "yes" : "no") << "\n";
}
} // namespace lib
#endif
vehicle.h
#ifndef _VEHICLE_H
#define _VEHICLE_H
#include <string>
class Vehicle {
public:
Vehicle(const std::string& manufacturer,
const std::string& model,
int year);
std::string manufacturer;
std::string model;
int year;
};
#endif
Following is implementation of vehicle.h file called vehicle.cpp
#include "vehicle.h"
#include "lib.h"
Vehicle::Vehicle(const std::string& manufacturer,
const std::string& model,
int year) :
manufacturer(manufacturer),
model(model),
year(year) {
::lib::isInit("Vehicle");
}
main.cpp
#include "vehicle.h"
#include "lib.h"
int main(int argc, char** argv) {
::lib::isInit("main");
::lib::initialized = true;
::lib::isInit("main");
Vehicle vehicle("Toyota", "Corolla", 2013);
return 0;
}
I am using g++
g++ -Wno-write-strings main.cpp vehicle.cpp -o bin/main.cpp.bin
I get following errors:
/tmp/cclVpsgT.o:(.bss+0x0): multiple definition of `lib::initialized'
/tmp/ccmJKImL.o:(.bss+0x0): first defined here
collect2: error: ld returned 1 exit status
I have checked the output of:
g++ -Wno-write-strings main.cpp vehicle.cpp -E
multiple definition occurs every time lib.h is included.
My questions are:
Why is lib.h included multiple times when define guard is there
How would I define 'extern' variable and initialize it in the same file (since it's used in the same file later)
Why is lib.h included multiple times when define guard is there
You need to remove the definition:
bool initialized = false;
And put it in one and only one source file.
Include guards prevent the same header file from getting included more than once in the same translation unit(TU) not in different translation units.
You define the variable initialized in header file which gets included across different translation units and then each TU has a symbol named initialized which breaks the one definition rule.
How would I define 'extern' variable and initialize it in the same file (since it's used in the same file later)
If you want the variable to be used in the same file, why make it extern? You need to use extern when you want to share the same variable accross different TUs.
If you need to use it at global scope in only single TU, You should simple put it inside a unnamed namespace.
I have a large project (20+ files) but I managed to set up this small example which recreates my problem. Essentially I have one file (A.cpp) including a second file (B.cpp), but that second file needs several of the variables and functions from the first file. Observe:
A.h:
#ifndef _A_H_
#define _A_H_
static void foo(int _something);
#endif // #ifndef _A_H_
A.cpp:
#include <iostream>
#include "A.h"
#include "B.h"
using namespace std;
static void foo(int _something)
{
cout << _something << "\n";
}
int main(int argc, char *argv[])
{
B *b;
foo ( 123 ); // So we don't get that pesky defined-not-used warning
b = new B ();
b->display ( 123 );
}
B.h:
#ifndef _B_H_
#define _B_H_
#include "A.h"
class B
{
public:
B();
~B();
void display ( int x );
};
#endif // #ifndef _B_H_
B.cpp:
#include "B.h"
void B::display ( int x )
{
foo ( x );
}
And I am compiling it like so, g++ -Wall A.cpp B.cpp -o main but then I get this error:
A.h:3:13: warning: ‘void foo(int)’ used but never defined [enabled by default]
/tmp/ccFwfZa6.o: In function `main':
A.cpp:(.text+0x54): undefined reference to `B::B()'
/tmp/ccM8SNBK.o: In function `B::display(int)':
B.cpp:(.text+0xd): undefined reference to `foo(int)'
collect2: ld returned 1 exit status
I can tell it's a link error, but I can't tell why I am getting that error.
EDIT:
In my original code I am still getting an error, this time it's about the multiple definition of an integer, here is the error I am getting:
B.o:(.bss+0x4): multiple definition of `some_var'
A.o:(.bss+0x4034): first defined here
collect2: error: ld returned 1 exit status
make: *** [main] Error 1
and I am creating the variable some_var like so
A.h:
#ifndef _A_H_
#define _A_H_
static void foo(int _something);
int some_var;
#endif // #ifndef _A_H_
How is it possible that some_var would get defined more than once when I have those conditional guards?
You have no B::B() body at all. Add one, and don't forget about destructor.
Also, remove static from foo().
The problem now is that each source file that #includes a.h gets a definition of int some_var;. In general, variables should be declared in headers and defined in one source file. So in your header you need
extern int some_var;
and in one source file (presumably a.cpp)
int some_var;
Thanks to Pete Becker I figured out the problem, and it stemmed mostly from a lack of understanding of all things C/C++.
extern statements are not meant to only be used in header files referencing other header files (ie. in "B.h" writing extern int a where a is defined in "A.c") but also in the original header files (in this case "A.h")
I thought, incorrectly, that a definition needed an equals sign (ie. int a = 1) whereas int a is also a definition. I was, thus, defining my variable in "A.h" when I should have been declaring it like so extern int a in "A.h".
After fixing the above 2, I kept getting undefined reference to a (I literally thought the compiler and linker were taking the piss). I was searching for int a=... in "A.cpp" and as clear as day it was being defined. Turns out this definition was inside a function, and therefore was never being defined.
If all else fails, edit your source files in a trivial way (ie. delete a word and type it again) to force a compilation) as I find changing the header files does not always result in full compilations.
I'm using Xcode to build a C++ project.
But I don't understand the error message:
"Apple Mach-O linker command failed with exit code 1"
I found that #include is the reason.
I have two .cpp file which include a same .h file. If I remove #include of one, it will be build successfully.
Other header files are fine expect the header file described above. I already used "ifndef".
#ifndef include guards only work at the level of the translation unit (usually a single source file).
If you define the same object twice in two translation units, that won't be fixed by include guards but the linker will complain bitterly when you try to combine the two object files into a single executable.
I suspect your situation is akin to:
hdr.h:
#ifndef HDR_H
#define HDR_H
void rc(void);
int xyzzy;
#endif
prog1.c:
#include "hdr.h"
#include "hdr.h"
int main (void) { rc(); return xyzzy; }
prog2.c:
#include "hdr.h"
void rc(void) { xyzzy = 0; }
In a situation like that, the include guard will prevent the header being included twice in prog1.c but it will still be included in both prog1.c and prog2.c, meaning that each will have a copy of xyzzy.
When you link them together, the linker will not like that.
The solution is to not define things in headers but to merely declare them there, leaving the definition for a C file:
hdr.h:
#ifndef HDR_H
#define HDR_H
int rc(void);
extern int xyzzy; // declare, not define
#endif
prog1.c:
#include "hdr.h"
#include "hdr.h"
int main (void) { rc(); return xyzzy; }
prog2.c:
#include "hdr.h"
int xyzzy; // define
int rc(void) { xyzzy = 0; }
Declarations are things like function prototypes, extern variables, typedefs and so on (simplistically, things that declare something exists without actually creating an "object").
Definition are things that create "objects", like non-extern variables and so on.
You need to track down what "object" is being defined twice (the linker output should have something like doubly-defined symbol 'xyzzy') and then make sure it's not defined in the header.
I have been trying to use extern in order to use variable that is previously defined.
I have not used extern before and now I need to use it in order to define variable just once and use them across multiple files
I have written minimized version of code for this question. I have four files
lib.h
#ifndef LIB_H
#define LIB_H
#include <iostream>
namespace lib {
extern bool initialized;
bool initialized = false;
static void isInit(char* parent) {
std::cout << "Library for [" << parent << "] initialized? " << (::lib::initialized ? "yes" : "no") << "\n";
}
} // namespace lib
#endif
vehicle.h
#ifndef _VEHICLE_H
#define _VEHICLE_H
#include <string>
class Vehicle {
public:
Vehicle(const std::string& manufacturer,
const std::string& model,
int year);
std::string manufacturer;
std::string model;
int year;
};
#endif
Following is implementation of vehicle.h file called vehicle.cpp
#include "vehicle.h"
#include "lib.h"
Vehicle::Vehicle(const std::string& manufacturer,
const std::string& model,
int year) :
manufacturer(manufacturer),
model(model),
year(year) {
::lib::isInit("Vehicle");
}
main.cpp
#include "vehicle.h"
#include "lib.h"
int main(int argc, char** argv) {
::lib::isInit("main");
::lib::initialized = true;
::lib::isInit("main");
Vehicle vehicle("Toyota", "Corolla", 2013);
return 0;
}
I am using g++
g++ -Wno-write-strings main.cpp vehicle.cpp -o bin/main.cpp.bin
I get following errors:
/tmp/cclVpsgT.o:(.bss+0x0): multiple definition of `lib::initialized'
/tmp/ccmJKImL.o:(.bss+0x0): first defined here
collect2: error: ld returned 1 exit status
I have checked the output of:
g++ -Wno-write-strings main.cpp vehicle.cpp -E
multiple definition occurs every time lib.h is included.
My questions are:
Why is lib.h included multiple times when define guard is there
How would I define 'extern' variable and initialize it in the same file (since it's used in the same file later)
Why is lib.h included multiple times when define guard is there
You need to remove the definition:
bool initialized = false;
And put it in one and only one source file.
Include guards prevent the same header file from getting included more than once in the same translation unit(TU) not in different translation units.
You define the variable initialized in header file which gets included across different translation units and then each TU has a symbol named initialized which breaks the one definition rule.
How would I define 'extern' variable and initialize it in the same file (since it's used in the same file later)
If you want the variable to be used in the same file, why make it extern? You need to use extern when you want to share the same variable accross different TUs.
If you need to use it at global scope in only single TU, You should simple put it inside a unnamed namespace.
I understand that pre-processor commands are an important part of header files to prevent vars and classes from being defined more than once.
I have been running into issues with my vars being defined multiple times - even with pre-processor wrappers. Here is a sample project that is experiencing compiler errors:
Header:
// TestInclude.h
#ifndef TESTINCLUDE_H_
#define TESTINCLUDE_H_
int myInt;
#endif /*TESTINCLUDE_H_*/
C++:
// TestInclude.cpp
#include <iostream>
#include "IncludeMe.h"
#include "TestInclude.h"
int main( int argc, char* args[] )
{
std::cin >> myInt;
IncludeMe thisClass;
std::cin >> myInt;
}
Header:
// IncludeMe.h
#ifndef INCLUDEME_H_
#define INCLUDEME_H_
class IncludeMe
{
private:
int privateInt;
public:
IncludeMe();
};
#endif /*INCLUDEME_H_*/
C++:
// IncludeMe.cpp
#include <iostream>
#include "IncludeMe.h"
#include "TestInclude.h"
IncludeMe::IncludeMe()
{
std::cout << "myInt: " << myInt;
}
Then I compile like this:
Makefile:
all:
g++ -g -o TestInclude TestInclude.cpp IncludeMe.cpp
And I get the following error:
/tmp/ccrcNqqO.o: In function `IncludeMe':
/home/quakkels/Projects/c++/TestInclude/IncludeMe.cpp:6: multiple definition of `myInt'
/tmp/ccgo6dVT.o:/home/quakkels/Projects/c++/TestInclude/TestInclude.cpp:7: first defined here
collect2: ld returned 1 exit status
make: *** [all] Error 1
Why am I getting this error when I'm using pre-processor conditionals in my header files?
Include guards do not protect against multiple definitions. They only protect against infinite recursive inclusion. (You can of course include the same header in multiple translation units!)
You should never have object definitions* in the header; only declarations:
header.hpp:
extern int a;
file.cpp:
#include "header.hpp"
int a = 12;
*) You can have class definitions in a header file, as well as inline functions and class member functions.
You should use extern int myInt; in header files and only write int myInt; in the single .cpp file where you want to define it.
Some projects use a preprocessor macro like "IN_FOO_CPP" to make that happen automatically with #ifdefs.