C++ Global Functions

Below is an example of how to write global functions in C++. These functions are intended to be used across multiple files.

util.h
#pragma once

int helper();



util.cpp
#include "util.h"

int helper()
{
	return 3;
}

Usage:

main.cpp
#include "util.h"

int main()
{
	int i = helper();
	return 0;
}

Do not put implementation in the header file

When the function is short, it is tempting to put the implementation in the header file and get rid of the cpp file:

util.h
#pragma once

int helper()
{
	return 3;
}

main.cpp
#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:

another.cpp
#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.obj
Error LNK1169 one or more multiply defined symbols found --- project.exe

The 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)

util.h
#pragma once

namespace
{
	int helper()
	{
		return 3;
	}
}
main.cpp
#include "util.h"

int main()
{
	int i = helper();
	return 0;
}


(2) Internal Linkage (using static keyword)

util.h
#pragma once

static int helper()
{
	return 3;
}

main.cpp
#include "util.h"

int main()
{
	int i = helper();
	return 0;
}

(3) Inline

util.h
#pragma once

inline int helper()
{
	return 3;
}

main.cpp
#include "util.h"

int main()
{
	int i = helper();
	return 0;
}

Put inline function implementation in header file

Correct:

util.h
#pragma once

inline int helper()
{
	return 3;
}

main.cpp
#include "util.h"

int main()
{
	int i = helper();
	return 0;
}

Incorrect:

util.h
#pragma once

int helper();



util.cpp
#include "util.h"

inline int helper()
{
	return 3;
}
main.cpp
#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.obj

Placing 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.

Use internal linkage for inline functions

Preferred 1:

util.h
#pragma once

namespace
{
	inline int helper()
	{
		return 3;
	}
}

Preferred 2:

util.h
#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.

a.cpp
inline int helper()
{
	return 0;
}

int a()
{
	return helper() + 100;
}
b.cpp
inline int helper()
{
	return 1;
}

int b()
{
	return helper() + 100;
}
main.cpp
#include <iostream>
int helper();

int main()
{
	std::cout << helper();
	return 0;
}
1>------ Build started: Project: Project1, Configuration: Debug Win32 ------
1>a.cpp
1>main.cpp
1>b.cpp
1>Generating Code...
1>Project1.vcxproj -> Project1.exe
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

Output: 0

1>------ Build started: Project: Project1, Configuration: Debug Win32 ------
1>main.cpp
1>b.cpp
1>a.cpp
1>Generating Code...
1>Project1.vcxproj -> Project1.exe
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

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.