Below is an example of how to write global functions in C++. These functions are intended to be used across multiple files.
#pragma once
int helper();
#include "util.h"
int helper()
{
return 3;
}
Usage:
#include "util.h"
int main()
{
int i = helper();
return 0;
}
When the function is short, it is tempting to put the implementation in the header file and get rid of the cpp file:
#pragma once
int helper()
{
return 3;
}
#include "util.h"
int main()
{
int i = helper();
return 0;
}
The above compiles and runs correctly until another cpp file that uses the same global function is added to the project:
#include "util.h"
#include <iostream>
void output()
{
std::cout << helper();
}
Output:
Error LNK2005 "int __cdecl helper(void)" (?helper@@YAHXZ) already defined in another.obj --- main.objThe above fails because main.obj (created from main.cpp) and
another.obj (created from another.cpp) both contain the same
helper
function implementation. When the linker tries to
create project.exe from main.obj and another.obj, there are two
helper
function definitions which is not allowed in C++.
Functions are external linkage by default. Include guards prevent including multiple identical header file contents into the same cpp file but they do not prevent the same function definition to appear across different translation units (cpp files). C++ requires one definition across all translation units (one-definition-rule). If there are reasons to put the implementation in the header file (such as for inlining or creating header-only libraries), use internal linkage and/or inline instead:
(1) Internal Linkage (using unnamed namespace)
#pragma once
namespace
{
int helper()
{
return 3;
}
}
#include "util.h"
int main()
{
int i = helper();
return 0;
}
(2) Internal Linkage (using static keyword)
#pragma once
static int helper()
{
return 3;
}
#include "util.h"
int main()
{
int i = helper();
return 0;
}
(3) Inline
#pragma once
inline int helper()
{
return 3;
}
#include "util.h"
int main()
{
int i = helper();
return 0;
}
Correct:
#pragma once
inline int helper()
{
return 3;
}
#include "util.h"
int main()
{
int i = helper();
return 0;
}
Incorrect:
#pragma once
int helper();
#include "util.h"
inline int helper()
{
return 3;
}
#include "util.h"
int main()
{
int i = helper();
return 0;
}
Output of incorrect case:
Error LNK2001 unresolved external symbol "int __cdecl helper(void)" (?helper@@YAHXZ) --- main.objPlacing the inline implementation in cpp file results in linker error. Function with inline keyword needs identical definition in every translation unit in which it is used. Here, main.cpp sees helper() declaration but lacks helper() definition.
Preferred 1:
#pragma once
namespace
{
inline int helper()
{
return 3;
}
}
Preferred 2:
#pragma once
static inline int helper()
{
return 3;
}
If the same inline function is defined differently across multiple cpp files, which implementation the resulting executable will execute is undefined. Below example shows how compilation order affects program output.
inline int helper()
{
return 0;
}
int a()
{
return helper() + 100;
}
inline int helper()
{
return 1;
}
int b()
{
return helper() + 100;
}
#include <iostream>
int helper();
int main()
{
std::cout << helper();
return 0;
}
Output: 0
1>------ Build started: Project: Project1, Configuration: Debug Win32 ------Output: 1
Functions default to external linkage whether they are defined inline or not. When the function is marked inline, the linker arbitrarily chooses one from the several definitions available from multiple object files. By marking the inline function as internal linkage, every translation unit uses its own implementation of the function, thus preventing the undefined behavior.