Mistakes do not all appear simultaneously in a C++ program. Some mistakes become evident while a single source file is being checked by the compiler, some only occur after the compiler and its linked companion have created object files, some only reveal themselves after a program has completed compilation and linking and has been executed, and other errors only emerge after a compiled and linked program starts running. Knowing which phase produced the diagnostic of an error greatly simplifies fixing the corresponding mistakes.
A compiler error is reported by the compiler prior to any object files being generated. The compiler has just examined the text of one translation unit and determined that some rule has been violated. A missing semicolon is one very common compiler error.
#include <iostream>
int main()
{
std::cout << "hello\n"
return 0;
}
The insertion statement is not terminated by a semicolon. The compiler reads into the next line where the end of the statement is not as expected. It reports that a semicolon is missing and that is an error and not to continue checking compilation for that one file.
At that point, the program will never be successfully linked together because no object file has been created since at that point on in compilation the file failed.
Fixing it would simply entail adding in the missing semicolon.
An undeclared name is the other very common compiler error. When the program fails to include the header that declares std::cout, then the compiler has no history of that name and would never have learned its definition:
int main()
{
std::cout << "hello\n";
return 0;
}
The compiler reports that std::cout is undeclared, stops work for that one translation unit, and thus never creates an object file from that source file. Fix it by adding the appropriate include statement: #include <iostream>.
The error presented by the linker is one that is encountered after the compiler has succeeded. Object files have been generated but when they were trying to be combined by the linker, it was noticed that not enough information was available. One pair of files illustrates.
// main.cpp
#include <iostream>
int add(int x, int y); // only a declaration
int main()
{
std::cout << add(2, 3) << '\n';
return 0;
}
// add.cpp
// (intentionally empty - no definition of add)
// (intentionally empty – no definition of add)
The main.cpp file compiled with no errors, as add is declared there even though its definition is elsewhere. Object file main.o is created, as are object files from all other compilation units as well. As soon as the linker is called, however, and it encounters the call to add in main.o, it can't see where that definition would be since the definition isn't in any of the object files produced by the compiler for that program, so it has to report undefined reference to add and then it fails to create the executable:
Fix this problem by ensuring that add is defined in add.cpp:
int add(int x, int y)
{
return x + y;
}
The runtime error refers to anything that occurs after the program has been compiled successfully and then executed, but the program is not error free. Perhaps it is reporting that an error is in fact occurring, or perhaps it is stating incorrectly what should be taking place. A simple way to report an error in a program is simply to make the return from main nonzero, to inform an executing program that it failed to run:
#include <iostream>
int main()
{
std::cout << "something went wrong\n";
return 1;
}
The compiler never flags this. The linker also never flags this because it is irrelevant and that's irrelevant until you want to check an executed program's return value. As an example, a simple loop would demonstrate error at runtime. The correct return value from main is zero, to report an error free execution and so anything greater than that may signal a failure.
Of course, the program could just be working incorrectly by outputting a value when a different value was expected based on some logic that the compiler was totally unaware of:
#include <iostream>
int main()
{
std::cout << 2 + 2 << '\n';
std::cout << "expected 5\n";
return 0;
}
The program works through from start to finish with no compiler or linker complaints. The program successfully created a binary and the binary ran correctly, but the output simply is not what was expected, and that is a runtime error. At some point, a programmer has to check the output of a program and compare it against what they expected.
Exercise: Compiler, Linker, and Runtime ErrorsStarter code, hints and solutionOpenClose
Practice: Compiler, Linker, and Runtime Errors
Work through the mission, reveal hints only when needed, and compare your result with the model solution.
Your challenge
Diagnose why this deliberately incomplete program cannot reach runtime. Classify the missing definition of add as a compile, link, or runtime problem; supply its body and predict what add(2, 3) prints.
Mission checklist
- Identify the declaration of add and the call that uses it.
- Explain why the missing definition is detected when linking.
- Supply the function body, compile and link, then compare the printed sum with your prediction.
Starter program
Intentional linker-error exercise: this file compiles to an object file, but cannot link by itself because add is declared and not defined. Diagnose the missing definition, then compare with the complete solution. No executable is produced until the error is fixed.
// main.cpp
#include <iostream>
int add(int x, int y); // only a declaration
int main()
{
std::cout << add(2, 3) << '\n';
return 0;
}Hints
The shown program declares add and calls add(2, 3), but never supplies its body. Decide whether the missing information is needed during compilation or linking.
A declaration tells C++ the parameter and return types; a definition supplies the work. This example cannot reach a runtime error until linking succeeds.
Worked solution
The missing function body is a linker problem, not an input error at runtime. The completed add definition returns x + y, so the repaired single-file program links and prints 5.
// main.cpp
#include <iostream>
int add(int x, int y); // only a declaration
int main()
{
std::cout << add(2, 3) << '\n';
return 0;
}
int add(int x, int y)
{
return x + y;
}
Example output
5
0 comments
No comments yet. Be the first.