Linker errors and the ODR
The header triple.h, guarded by #pragma once, holds not a declaration but a definition: int triple(int x) { return x * 3; }. Two files include it—report.cpp and this main.cpp:
#include <iostream>
#include "triple.h" // ✗
int main() {
std::cout << triple(14) << '\n';
}Each file compiles without errors, but the build clang++ main.cpp report.cpp stops at linking:
multiple definition of `triple(int)'The one definition rule
The linker joins the object files of all translation units into one program. In the office, it is the bookbinder who sews every department's folder into one book. Each of the two units got its own definition of triple from the header, and the book ended up with two pages holding the body of one function. The linker does not pick one of them; it stops the build.
The one definition rule, ODR for short, forbids this: a function has at most one definition per program, and exactly one if called. #pragma once does not help here: the mark sits on one folder, while the copies sit in different translation units.
Switch what triple.h holds and see at which step the build stops.
#pragma once int triple(int x) { return x * 3;}
#include <iostream>#include "triple.h" int main() { std::cout << triple(14) << '\n';}
#include "triple.h" int report() { return triple(2);}
#include <iostream>standard header#include "triple.h"waiting- int main() {
- std::cout << triple(14) << '\n';
- }
#include "triple.h"waiting- int report() {
- return triple(2);
- }
The preprocessor walks the #include lines from top to bottom and puts each file's text in place of the line. Press the button.
The rule can be broken from the other side too. If triple.h holds only a declaration and the build command leaves out triple.cpp, every file still compiles: each has the declaration. Then the linker reports undefined reference, or undefined symbol in the course exercises. It names the function, not the file: find the .cpp file that defines it and check that the command lists it.
inline in a header
If the definition has to stay in the header, the function is declared inline:
#pragma once
inline int triple(int x) {
return x * 3;
}The word inline lets a function's definition repeat in different translation units, as long as all the copies are identical. Copies from one header are always identical, and the linker keeps one of them. constexpr functions count as inline too, so they are defined right in headers. Other functions are usually split: the declaration goes in the header, the definition in a .cpp file.
Common mistake
A .cpp file is included instead of the header:
#include <iostream>
#include "triple.cpp" // ✗
int main() {
std::cout << triple(14) << '\n';
}main.cpp itself compiles, but the build clang++ main.cpp triple.cpp fails with multiple definition again. The definition of triple ended up in two translation units: in triple.cpp and in main.cpp, where #include pasted it. Include the header triple.h, and pass .cpp files only to the build command. The tests in the course exercises do include your solution's .cpp file, but there the whole build is one translation unit.
Key points
- The linker joins the object files of all translation units into one program.
- Under the one definition rule, a called function has exactly one definition in the program.
- A definition in a header without
inlinelands in every unit and causesmultiple definition. - A
.cppfile left out of the build command causesundefined reference, orundefined symbolin the course exercises.
Subscribe to take the course
The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.