Skip to content
VLSI Mentor

C++ Part I · Module 2 · Building and Running C++ Programs

Compiling and Running from the Command Line

Chapter 2.2 handed you a build command and asked you to use it on trust. This chapter pays that back. Four options appeared on that line, and none of them is decoration: one chooses which version of C++ you are writing, one names the file you get, and two decide whether the compiler tells you about problems it has already noticed. That last pair is the important one, and rather than arguing for it we will compile a program two ways — once with the options and once without — and look at what the compiler says each time and what the program then prints. Learning to drive the compiler yourself is worth the half hour even if you spend your working life inside an IDE, because an IDE's build button is this command with the options chosen by somebody else, and when a build behaves differently on your machine than on a colleague's, the difference is almost always in options you could not see.

Foundation14 min readC++Part IToolchainCompiler

Part I · Module 2 · Chapter 2.3 · Compiling and Running from the Command Line

1. The Command

Here is the line again, with every part labelled:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
c++ -std=c++17 -Wall -Wextra -Wpedantic hello.cpp -o hello
│   │          │                        │         │
│   │          │                        │         └── name the output file
│   │          │                        └── the source file to build
│   │          └── report problems you have noticed
│   └── which version of C++ this is
└── the program that does the work

Then you run the result:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
$ ./hello

The ./ is not part of C++. It tells the shell to run the program in the current directory, rather than searching the directories it normally searches for commands.

Four options, taken in order of how much trouble each one saves you.

2. c++, g++, clang++ — Which to Type

All three names refer to a C++ compiler driver. On most Unix-like systems:

  • g++ is GCC's C++ compiler.
  • clang++ is Clang's.
  • c++ is usually a link to whichever of the two your system treats as the default.

For everything in this curriculum they are interchangeable. Use whichever you have. If you are not sure what you have, ask it:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
$ c++ --version

The word driver is worth keeping. c++ is not itself the compiler — it is a program that runs several other programs in the right order and passes the results along. Chapter 1.7 §3 said one command is not one operation, and Chapter 2.6 opens the sequence up and shows you each intermediate file.

3. -std=c++17 — Not Optional

This option chooses the version of the language.

Chapter 1.3 established why the version matters and why this curriculum fixes on C++17. Here is what happens when you get it wrong, which is more instructive than the argument.

This program uses an if statement with an initialiser — a C++17 feature:

Azvya Education Pvt. Ltd.VLSI Mentor
std17.cpp — complete program, uses one C++17 feature
#include <iostream>

int main()
{
    if (int difference = 42 - 40; difference != 0) {   // C++17
        std::cout << "difference = " << difference << '\n';
    }
    return 0;
}

Three builds, three different outcomes on the machine used for this chapter:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
$ c++ -std=c++17 -Wall -Wextra -Wpedantic std17.cpp -o std17
$ ./std17
difference = 2

$ c++ -std=c++11 std17.cpp -o std17
std17.cpp:5:9: warning: 'if' initialization statements are a C++17 extension
                        [-Wc++17-extensions]
                                                    ← and it still builds

$ c++ -std=c++11 -pedantic-errors std17.cpp -o std17
std17.cpp:5:9: error: 'if' initialization statements are a C++17 extension
                      [-Werror,-Wc++17-extensions]

Read the middle one carefully, because it is the trap. You asked for C++11, you used a C++17 feature, and the compiler built it anyway and only mentioned the problem in passing. Many people never see that line scroll past.

That is the situation Chapter 1.3 §6 described: your compiler accepts more than the standard you named, so code that looks portable is not, and you find out when it reaches a toolchain that is stricter or older. The third build is how you find out early.

Two practical rules follow:

  • Always name the standard. With no -std at all, the compiler picks a default that varies by compiler and by version, and that default usually includes extensions. "It built on my machine" then tells you nothing about anyone else's.
  • Put it in the build file, not in your shell history. Module 24.7 and 24.8 cover where it belongs in a real project. For now, type it every time.

4. -o — Naming the Output

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-o hello

Without -o, the compiler writes a file called a.out — a default inherited from very old Unix. It works, and it means every program you build overwrites the last one.

With -o hello you get a file called hello. Name it after what it is.

That is the whole of this option, with one thing worth knowing: -o names whatever the current command produces, and that is not always a program. In Chapter 2.6 the same option names a preprocessed file, an assembly file and an object file, depending on which stage you asked the driver to stop at.

5. -Wall -Wextra -Wpedantic — The Ones That Earn Their Keep

Here is the demonstration. This program compiles. It is also wrong.

Azvya Education Pvt. Ltd.VLSI Mentor
warn.cpp — complete program, compiles, contains a real bug
#include <iostream>

int main()
{
    int cycle_count = 0;
    int error_count;                  // never given a value

    std::cout << "cycles = " << cycle_count << '\n';
    std::cout << "errors = " << error_count << '\n';

    return 0;
}

error_count is declared and never given a value, and then it is printed.

Build it with no warning options:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
$ c++ -std=c++17 warn.cpp -o warn
$                                    ← nothing. Not one word.

The compiler said nothing at all. Now run it:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
$ ./warn
cycles = 0
errors = 1

errors = 1. There is no 1 anywhere in that program. The value is whatever happened to be in that storage, and reading it is undefined behaviour — Chapter 1.3 §5 is where that term was made precise.

Now build the same file with the warning options:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
$ c++ -std=c++17 -Wall -Wextra -Wpedantic warn.cpp -o warn
warn.cpp:9:33: warning: variable 'error_count' is uninitialized when used here
                        [-Wuninitialized]

The file, the line, the column, the variable by name, and the category of problem. The compiler knew the whole time. Nobody had asked it to say so.

That is the argument, and it is not really about these three options. It is about what a compiler is for:

A compiler is not only a translator. It is the cheapest code reviewer you will ever have, and warnings are the only way it can talk to you about code that is legal but probably wrong.

What each one does:

OptionWhat it adds
-WallThe core set of warnings for likely mistakes. Despite the name, this is not all warnings.
-WextraA further set -Wall leaves out, including unused parameters and some comparison problems.
-WpedanticTells you when you have used a compiler extension rather than standard C++ — the §3 trap.

6. One More Stop: -c

One option you will meet in Chapter 2.6, mentioned here so it is not a surprise:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
$ c++ -std=c++17 -Wall -Wextra -Wpedantic -c hello.cpp -o hello.o

-c means "compile, but do not produce a program". You get an object file instead — a .o. It contains machine code and it cannot be run.

That is all this chapter says about it. Chapter 2.6 explains what an object file is for and why building a real project almost always goes through this step.

7. This Command Line Is Not Universal

Everything above is the GCC and Clang spelling, which covers Linux, macOS and most cross-compilers for embedded targets. It is not the only one.

Microsoft's compiler, cl.exe, uses different options for the same ideas: /std:c++17, /W4, /Fe for the output name. The concepts transfer exactly; the spellings do not.

This matters in practice because of where C++ runs in this field. A reference model that is built by a simulator's own toolchain on Linux, by a developer on Windows, and by a cross-compiler for an embedded target is being handed to three different drivers with three different option spellings — which is one of several reasons real projects describe the build in a build file rather than a command. Module 24.8 is that chapter.

8. Mistakes Worth Making Once

Omitting -std and assuming the default. The default varies and usually allows extensions. Your code may rely on something the standard does not have, and you will not find out on your machine.

Treating -Wall as "all warnings". It is not; the name is historical. -Wall -Wextra together is the useful baseline, and even that is not exhaustive.

Scrolling past warnings because the program ran. warn.cpp ran. It printed a number that does not exist in the source. "It worked" and "it is correct" are different claims, and a warning is the compiler telling you which one you have.

Using gcc or cc on a .cpp file. Your code compiles fine and then the link fails with a long list of undefined std:: symbols. The cause is the driver, not your code — and note that it fails at the end, which is why the output looks so much worse than the mistake.

Rebuilding and running the old program. If a build fails, the previous hello is still sitting there and ./hello will happily run it. You then debug behaviour you already fixed. Check that the build succeeded before you believe the run.

9. What You Should Be Able to Say Now

  1. c++, g++ and clang++ are compiler drivers — programs that run several tools in order. For this curriculum they are interchangeable.
  2. gcc and cc are the C drivers; using them on a .cpp file fails at the end with undefined std:: symbols.
  3. -std=c++17 chooses the language version. Without it the default varies and usually allows extensions.
  4. A newer feature under an older -std may produce only a warning and still build. -pedantic-errors makes it an error.
  5. -o names the output. Without it you get a.out, and every build overwrites the last.
  6. -Wall -Wextra -Wpedantic ask the compiler to report problems it has already noticed.
  7. Measured: a program reading an uninitialised variable compiled silently without them, printed a garbage 1, and was pinpointed by file, line, column and variable name with them.
  8. A warning is a defect report. A project with hundreds of warnings has none, because nobody reads them.
  9. -c stops before producing a program and gives an object file. Chapter 2.6 uses it.
  10. These option spellings are GCC/Clang. MSVC expresses the same ideas differently, which is one reason projects use build files.

10. Exercises

Exercise 1 — read the command. For c++ -std=c++17 -Wall -Wextra -Wpedantic check.cpp -o check, name what each of the six parts does in one short phrase each.

Exercise 2 — predict the three builds. A file uses one C++17 feature. Say what happens under (a) -std=c++17, (b) -std=c++11, (c) -std=c++11 -pedantic-errors, and which of the three is most dangerous to a team and why.

Exercise 3 — justify the flags to a sceptic. A colleague says warnings are noise because the code compiles and runs. Using §5, give the specific evidence. Your answer should name what the program printed and why that value existed.

Exercise 4 — diagnose from the symptom alone. A build of a .cpp file ends with a long list of undefined symbols, nearly all of which mention std::, followed by a line beginning ld:. The same source builds fine for a colleague. What do you check first, and why does that symptom point there rather than at the code?

Exercise 5 — the stale program. Explain how a failed build can lead someone to debug behaviour they already fixed, and give the one-line habit that prevents it.

Exercise 6 — which is the bug? In warn.cpp, is the defect the missing initialisation, the missing warning flags, or both? Defend your answer in two sentences.

11. Summary

  • c++ is a driver, not the compiler: it runs several tools in order. Use the C++ driver, never gcc/cc, on a .cpp file.
  • -std=c++17 is not optional. Defaults vary and allow extensions, and a newer feature under an older -std may only warn — -pedantic-errors makes it fail.
  • -o names the output, and in Chapter 2.6 it will name intermediate files too.
  • -Wall -Wextra -Wpedantic are the ones that earn their keep. Measured: total silence without them on a program that printed a garbage value; file, line, column and variable name with them.
  • A warning is a defect report. Hundreds of warnings means none.
  • -c stops early and gives an object file — the subject of Chapter 2.6.
  • These spellings are GCC/Clang. The concepts transfer to MSVC; the options do not.

You can now build a single file deliberately and make the compiler tell you what it knows. The next limit is the file itself: everything so far has lived in one .cpp, and no real program does. Chapter 2.4 splits a program across two files, which immediately raises a question one file never asks — how does the code in one file know that a function in the other one exists?

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.