C++ Part I · Module 2 · Building and Running C++ Programs
The Structure of a C++ Program
Module 1 was orientation. It taught you what C++ is, why it exists, and where it is used, but it deliberately taught no C++ you could write. That changes here. This chapter looks at the smallest complete C++ program there is — one line long — and accounts for every piece of it. Where does a program start? What does the number at the end actually do? What makes a statement a statement? You will also meet one rule that applies to main and to nothing else in the language, and which surprises people who learn it by accident years later. We will be honest about one more thing: a real program has parts this one does not, and some of those parts cannot be explained properly yet. Those get named rather than hand-waved, with the chapter that makes each one precise.
Foundation12 min readC++Part IFundamentalsProgram Structure
Part I · Module 2 · Chapter 2.1 · The Structure of a C++ Program
1. The Smallest Complete Program
This is a whole C++ program. Nothing is missing from it:
int main() { return 0; }It compiles. It runs. It does nothing visible, which is fine — doing nothing visible is a perfectly good thing for a program to do while you are learning what the parts are.
Most tutorials start with a program that prints text. We are not doing that yet, and the reason is practical. A printing program needs an #include line and a stream object, and explaining those properly takes three more chapters. Starting without them means every character on the page above can be explained right now, with nothing deferred.
So: four pieces of punctuation and three words. Let us take them in order.
2. Execution Starts at main
A program needs a place to begin. In C++ that place is a function called main.
You do not call main yourself. When you run the program, the system starts it, some setup happens, and then main is called for you. When main finishes, the program ends.
That gives you the first durable rule:
mainis where your program starts and where it ends. Every C++ program that runs on its own has exactly onemain.
Two consequences follow, and both come up in practice:
- Exactly one. Not zero, not two. A program with no
mainhas no starting point, and a program with two has an ambiguous one. Both fail to build, and Chapter 2.7 shows you what each failure looks like. - The name is fixed.
mainis not a convention you could change by renaming it.Main,MAINandstartare different names, and none of them is the starting point.
You will write other functions later — Module 6 is about them properly. They run only when something calls them, directly or indirectly, starting from main.
3. What the Number Means
Look at the two ends of the line:
int main() { return 0; }
// ^ ^
// | └── the value handed back
// └── the kind of value main hands backThe int at the front says main hands back a whole number. The return 0; at the end is where it does so.
Hand it back to whom? Not to another part of your program — nothing in your code called main. It goes to whatever started the program: your terminal, a build script, a regression runner, a continuous-integration job.
That number is called the program's exit code or exit status, and the convention is simple and near-universal:
0means success.- Anything else means failure, and the particular non-zero value can say which kind of failure.
This is not decoration. It is how one program tells another whether it worked. A regression script that runs two hundred simulation checks does not read their console output to decide whether they passed — it reads their exit codes.
Here is a program that reports failure:
int main()
{
return 3;
}On a Unix-like shell you can see the code it returned. The shell stores the last program's exit status in $?:
$ ./exit3
$ echo $?
3Nothing was printed, and the program still communicated something. That is the point of the exit code: it works when there is nobody watching the screen.
4. Statements, Semicolons and the Block
Between the braces is the body of main — the work it does.
return 0; is a statement: one complete instruction. In C++ a statement ends with a semicolon. The semicolon is not punctuation the way a full stop is in English; it is how the compiler knows one instruction has finished and the next begins.
The braces { and } mark a block: a group of statements treated as one unit. main's body is a block. A block can hold one statement, many, or none.
Spreading the same program over several lines changes nothing:
int main()
{
return 0;
}This is the same program as the one-liner in §1. The compiler sees the same sequence of words and punctuation either way. Line breaks and indentation exist for the people reading the code, and the compiler ignores them.
That freedom is worth stating plainly, because it is the reason formatting is a team decision rather than a language rule: the compiler does not care, so you should, and consistently.
One thing that is not free: you cannot split a word. int main is two words; in t main is an error. Whitespace separates things, it does not get inserted into them.
5. The One Rule That Applies Only to main
Here is a program with no return statement at all:
int main()
{
}It compiles cleanly, with -Wall -Wextra -Wpedantic and no warnings. And when you run it:
$ ./min2
$ echo $?
0It returned 0 — the success value — even though nothing in the source says so.
This is a real rule in the C++ standard, and it is special to main. If control reaches the end of main without hitting a return, the effect is the same as return 0;. The language inserts it for you.
6. Comments
Two forms, both ignored entirely by the compiler:
int main()
{
// Everything after two slashes, to the end of the line.
/* This form starts here
and runs until the closing marker. */
return 0;
}The first form is what you will use almost always. The second is useful when you want to comment out a block temporarily, though it does not nest — a /* inside a /* ... */ does not start a second comment, and the first */ ends the whole thing. That catches people out.
A note on what comments are for, since it shapes everything you write later. A comment that restates the code is noise:
return 0; // return zeroA comment that says something the code cannot is valuable:
return 3; // 3 = input file could not be opened; see docs/exit-codes.mdThe second one records a decision. The first one is a line that can go out of date and tells you nothing while it is still accurate.
7. What a Real Program Adds
Our program is complete but minimal. A program that does something useful has more parts, and it is worth seeing them named now so they are not a surprise:
#include <iostream> // 1. bring in something defined elsewhere
int cycles_for(int transfers); // 2. your own function, declared
int main() // 3. the starting point
{
int result = cycles_for(8); // 4. a variable, and a call
std::cout << result << '\n'; // 5. output
return 0;
}
int cycles_for(int transfers) // 6. your own function, defined
{
return 3 + transfers * 2;
}You are not expected to write this yet. Each numbered piece has an owner:
| Piece | What it is, roughly | Taught properly in |
|---|---|---|
#include <iostream> | Pulls in code and names written elsewhere | 2.4, and 2.5 for what it literally does |
int cycles_for(int); | Tells the compiler a function exists before it is used | 2.4, Module 6 |
int main() | The starting point | This chapter |
int result = ... | A named piece of storage holding a value | Module 3 |
std::cout << ... | Sending a value to the console | 2.2, 2.8 |
| the function body | Work packaged under a name | Module 6 |
Three of those six are provisional right now, and this curriculum will keep saying so rather than letting you assume you understand something you have only seen. When Chapter 2.2 uses std::cout, it will tell you exactly how much of it you are being asked to take on trust and for how long.
8. Mistakes Worth Making Once
Believing main is called by your code. It is not. Nothing in your source calls it. The system starts the program, the runtime does its setup, and main is called from outside your program entirely. This matters later: when Module 7 asks when a static object is initialised, "before main runs" is a meaningful answer, and it only makes sense if you know main is not the first thing that happens.
Thinking the exit code is the printed output. They are completely separate channels. A program can print "all tests passed" and return 1. The script that runs it will believe the 1. Make them agree.
Dropping the semicolon. The compiler will not stop at the end of the line looking for one — it keeps reading, and the error it reports is often on the next line, where the combined text finally stops making sense. Chapter 2.7 covers why the reported line is sometimes one past the real mistake.
Leaving out return 0; and then doing the same in another function. The rule in §5 applies to main alone. Carrying the habit elsewhere produces a function that promises a value and does not deliver one.
9. What You Should Be Able to Say Now
int main() { return 0; }is a complete C++ program.- Execution starts at
main. Every runnable program has exactly one, the name is fixed, and your code never calls it. intbeforemainsays it hands back a whole number;return 0;is where it does.- That number is the exit code, read by whatever started the program.
0means success and any other value means a specific failure. - A statement is one instruction and ends with a semicolon. A block is a group of statements in braces.
- Line breaks and indentation are for readers. The compiler ignores them, which is why formatting is a team decision.
- If control reaches the end of
mainwithout areturn, the effect isreturn 0;. This rule is special tomain; in any other value-returning function, falling off the end is undefined behaviour. - Write
return 0;anyway, to keep the habit correct everywhere else. - Comments are ignored by the compiler. Write them to record decisions, not to restate the code.
10. Exercises
Exercise 1 — predict the exit code. For each program, say what echo $? prints after running it, and why: (a) int main() { return 0; } (b) int main() { } (c) int main() { return 7; }.
Exercise 2 — one program or two? Are these the same program? Explain what the compiler sees in each case.
int main() { return 0; }int
main
(
)
{
return 0;
}Exercise 3 — spot the dangerous habit. A colleague writes a function that is supposed to return an int and forgets the return. They point out that their main has no return either and works fine. Explain in two sentences why the two cases are not the same.
Exercise 4 — design an exit code. You are writing a tool that checks a register dump against expected values. It can succeed, fail to open the file, or find mismatches. Propose an exit code for each outcome and say why you chose 0 for the one you did.
Exercise 5 — judge the comments. Which of these is worth writing, and why?
return 2; // returns 2
return 2; // 2 = mismatch found; the regression script retries on 2 onlyExercise 6 — the missing starting point. Without compiling, predict what happens if a file contains a correct function called start and no main at all. Say which tool reports the problem, and then check your answer against Chapter 1.7 §4 or Chapter 2.7.
11. Summary
int main() { return 0; }is a complete program. Everything else is addition.mainis the starting point, there is exactly one, the name is fixed, and your code never calls it.- The returned number is the exit code, read by whatever started the program.
0is success; other values name specific failures. - Statements end with semicolons; blocks group them in braces. Whitespace and line breaks are for the reader.
mainmay omit itsreturnand still return 0 — the only function in the language that may. Write it anyway.- Comments record decisions, not restatements of the code.
You can now read the skeleton of a program and say what each part is for. What the skeleton cannot do is tell you anything — it runs and ends in silence, and a program you cannot observe is a program you cannot learn from. Chapter 2.2 writes the first program that produces output, accounts for every character of the new line that makes it possible, and then builds and runs it so you have an edit-build-run loop of your own.
Standards & specifications
- Governing standard
- ISO/IEC 14882 (the C++ language standard)(opens ISO/IEC (JTC 1/SC 22/WG 21) in a new tab)
Defines the C++ language and its standard library — the type system and templates, the object model and object lifetime, initialisation and overload resolution, the memory model and the containers, algorithms and utilities the library provides. Like C's standard it is a FAMILY of editions (C++98/03, C++11, C++14, C++17, C++20, C++23) and the editions are NOT interchangeable: a feature this curriculum relies on may be unavailable, differently specified or merely proposed in another edition, so each lesson names the edition its claim depends on. It does not define any foreign-function interface to a hardware description language, nor what a compiler actually emits, nor platform behaviour on real silicon — those are the implementation's and the device's contracts. Working drafts published by WG21 are freely available and are what most engineers read day to day; a draft is not the published standard.
This page also covers RTL structure, verification approach and debugging technique. Those are engineering practice built on the standard, not requirements the standard itself imposes.
Where this fits
Part of the C++ Programming curriculum.
