Global function definition in header file - how to avoid duplicated symbol linkage error
Use the inline
keyword.
inline std::ostream& operator<< (std::ostream& o, const error_code& e) {
return o << "[" << e.hi << "," << e.lo << "]";
}
Why does global variables in a header file cause link error?
Lines like
const char *Bittorrent = "BitTorrent protocol";
const char eight_byte[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
define theses global variables no matter if that codes is in header file or ine a .c directly (#include
is just textual insertion of the header's contents).
Instead you should have the definitions in exaclty one source file and change the header to provide an extern
declaration instead:
extern const char *Bittorrent;
extern const char *eight_byte;
Then all your sources using thes variables can be compiled but the linker will the variables once only.
Duplicate Symbol when including header only library more than once
As alk already commented, you need to declare the functions and global variables in the header file static
.
The static
keyword means the object (function or variable) has internal linkage; that it is only visible in the current compilation unit, and it will not be included in any symbol tables.
It is also a good idea to use include guards, so that if you have another header file that includes your header, and the C source file includes both your header file and that other header file, your header file only gets included once. (The lines with FOOLIB_H
comprise the include guard in the below example.)
Consider the following trivial fixed-size stack example, foolib.h:
#ifndef FOOLIB_H
#define FOOLIB_H
#include <stdlib.h>
#define STACK_MAX 256
static size_t stack_size = 0;
static double stack_item[STACK_MAX];
static inline int stack_push(const double item)
{
if (stack_size < STACK_MAX) {
stack_item[stack_size++] = item;
return 0;
} else
return -1;
}
static inline double stack_pop(const double empty)
{
if (stack_size > 0)
return stack_item[--stack_size];
else
return empty;
}
#endif /* FOOLIB_H */
Each compilation unit (each source file you compile separately) that includes the above (#include "foolib.h"
), gets their own local private stack they can use via stack_push()
and stack_pop()
.
The reason for marking the functions static inline
rather than just static
is that the former tells the compiler that it is okay to omit the function altogether, if it is not used. In particular, if you compile code with gcc -Wall
, gcc warns if a static
function is not used, but does not warn if a static inline
function is not used. Other than that, there is not much practical difference.
duplicate symbol of a function defined in a header file
If I make it inline, the linker errors go away. That's not something I want to rely on, since inline is a request not a guarantee.
It's OK to inline the function.
Even if the object code is not inlined, the language guarantees that is will not cause linker errors or undefined behavior as long as the function is somehow not altered in different translation units.
If you #include
the .hpp in hundreds of .cpp files, you may notice a bit of code bloat but the program is still correct.
What causes this behavior? I'm not dealing with a scenario where I'm returning some kind of singleton.
The #include
mechanism is a convenience for reducing the amount of code you have to manually create in multiple files with the exact content. In the end, all translation units that #include
other files get the lines of code from the files they #include
.
If you #include
file_ops.hpp in, let's say, file1.cpp and file2.cpp, it's as if you have:
file1.cpp:
bool systemIsLittleEndian() {
uint16_t x = 0x0011;
uint8_t *half_x = (uint8_t *) &x;
if (*half_x == 0x11)
return true;
else
return false;
}
file2.cpp:
bool systemIsLittleEndian() {
uint16_t x = 0x0011;
uint8_t *half_x = (uint8_t *) &x;
if (*half_x == 0x11)
return true;
else
return false;
}
When you compile those two .cpp files and link them together to create an executable, the linker notices that there are two definitions of the function named systemIsLittleEndian
. That's the source of the linker error.
One solution without using inline
One solution to your problem, without using inline
, is:
- Declare the function in the .hpp file.
- Define it in the appropriate .cpp file..
file_ops.hpp:
bool systemIsLittleEndian(); // Just the declaration.
file_ops.cpp:
#include "file_ops.hpp"
// The definition.
bool systemIsLittleEndian() {
uint16_t x = 0x0011;
uint8_t *half_x = (uint8_t *) &x;
if (*half_x == 0x11)
return true;
else
return false;
}
Update
Regarding
bool MY_LIB_EXPORT someFunc();// implemented in `file_ops.cpp`
There is lots of information on the web regarding. This is a Microsoft/Windows issue. Here are couple of starting points to learn about it.
- Exporting from a DLL Using __declspec(dllexport)
- Importing into an Application Using __declspec(dllimport)
Global objects in C++ says duplicate symbols
If you really need to declare global objects in header, then try this:
// Test.h
#ifndef TEST_H
#define TEST_H
#include <iostream>
using namespace std;
class Test {
public:
Test();
~Test();
void setName(string);
string getName();
private:
string name;
};
extern Test test1, test2; // This is what I called a `global object`
#endif
Now in the implementation file (Test.cpp), define them:
// Test.cpp
Test test1, test2;
// continue your implementation of the class Test as earlier
How to fix duplicated functions in object files?
In your wrapper.h
extern char key;
void printUI();
void RunApplication();
PersonalInfo CreatePersonalInfo(std::string &, std::string &, int & );
ContactInfo CreateContactInfo(std::string &, std::string &, std::string &, int&);
void DisplayAllCustomers();
void AddCustomerToList(Customer &);
Customer CreateCustomer(PersonalInfo &, ContactInfo &);
extern std::vector<Customer> customers;
And declare both in One and only one .cpp file.
If you got C++17 you can just exchange the extern with inline
and your done.
Related Topics
C++ Static Template Member, One Instance for Each Template Type
Assertion Failed (Size.Width>0 && Size.Height>0)
How to Solve Memory Fragmentation
Declare Variables at Top of Function or in Separate Scopes
What Is the Purpose of _Cxa_Pure_Virtual
C++: Deep Copying a Base Class Pointer
Portable Unused Parameter MACro Used on Function Signature for C and C++
Is There Any Way a C/C++ Program Can Crash Before Main()
Write Concurrently Vector<Bool>
How to Building Static Qt with Static Openssl
Compute Objects Moving with Arrows and Mouse
Why Would I Prefer Using Vector to Deque
Windows/C++: How to Find the Line of Code Where Exception Was Thrown Having "Exception Offset"
Is !! a Safe Way to Convert to Bool in C++