Menu

Compiling C++: From Source to an Executable with g++

How C++ turns .cpp source into a native executable: compile with g++ (or clang++/MSVC), run the binary, and read the compiler errors when it goes wrong.

This page includes runnable editors - edit, run, and see output instantly.

Compile, Then Run

Now that you have a compiler installed, getting a C++ program to run is a two-step cycle. Unlike a scripting language where an interpreter reads your file line by line, C++ first compiles your source into a native executable - a standalone binary of machine code - and then you run that binary directly. There is no interpreter sitting between your program and the CPU at runtime.

That separation is why C++ is fast, and also why a syntax mistake stops you at compile time instead of halfway through a run. The compiler checks the whole file before producing anything.

You can run any self-contained example right here on the page - the editor below compiles and runs it for you. But it's worth knowing what happens on your own machine, because that's where real projects live.

The Compile-and-Run Cycle on Your Machine

Say you've saved this as main.cpp:

#include <iostream>
using namespace std;

int main() {
    cout << "Hello from the terminal" << endl;
    return 0;
}

Open a terminal in the folder that holds the file and invoke the compiler. The most common compiler is g++ (part of GCC); clang++ works identically for everything here:

g++ main.cpp -o main

If the code compiles cleanly, g++ prints nothing and creates a new file next to your source: an executable called main (or main.exe on Windows). That binary is machine code - not readable text, and tied to your operating system and CPU. Now run it:

./main
Hello from the terminal

On Windows you'd run it as main.exe (or just main) from the same terminal. The ./ on macOS and Linux tells the shell "the program is right here in this folder, not somewhere on the PATH" - a step beginners forget, then wonder why main says command not found.

What -o Does (and a.out)

The -o flag names the output. Drop it and g++ still compiles, but it writes the executable to a default name: a.out on macOS/Linux, a.exe on Windows.

g++ main.cpp        # produces a.out, not main
./a.out

This trips people up constantly: they compile, see no errors, run ./main, and get No such file or directory - because the binary is actually called a.out. Always pass -o so you know exactly what you're running.

You compile once per change to the source. After that, the executable is independent - you can run ./main a hundred times without recompiling. You only run g++ again after you edit the .cpp file.

Choosing a C++ Standard

C++ has versions - C++11, C++14, C++17, C++20, C++23 - each adding language features. The catch: your compiler picks a default standard that may be older than you expect, so modern code can fail to compile for no obvious reason. Set the standard explicitly with -std:

g++ -std=c++17 main.cpp -o main
g++ -std=c++20 main.cpp -o main

Here's code that uses a C++17 feature (structured bindings). It compiles fine in the editor, but on your machine it needs -std=c++17 or newer:

If you ever see an error like 'structured bindings' only available with '-std=c++17', the fix is not in your code - it's adding the right -std flag. Throughout this course, assume C++17 or newer.

Turn On Warnings

A C++ program can compile cleanly and still be wrong. The compiler will, if you ask, point out suspicious code before it bites you at runtime. Add -Wall -Wextra:

g++ -std=c++17 -Wall -Wextra main.cpp -o main

Consider this program. It compiles without -Wall, but it has a real bug - reading a variable that was never given a value, which is undefined behavior:

#include <iostream>
using namespace std;

int main() {
    int count;                 // never initialized
    cout << count << endl;     // reads garbage - undefined behavior
    return 0;
}

With warnings on, the compiler flags it:

warning: 'count' is used uninitialized [-Wuninitialized]

Get into the habit of compiling with -Wall -Wextra from day one. Warnings are the compiler doing free code review; ignoring them is how subtle bugs survive. The fix here is simply int count = 0;.

Reading Compiler Errors

When g++ rejects your code, it names the file, the line, and what went wrong. Learning to read those messages is half of getting unstuck. Here's the classic - a missing semicolon:

#include <iostream>
using namespace std;

int main() {
    cout << "Oops"      // no semicolon
    return 0;
}
main.cpp:5:5: error: expected ';' before 'return'
    5 |     return 0;
      |     ^~~~~~

A few things to notice. The error reports line 5, but the mistake is on line 4 - the compiler only realizes a semicolon is missing once it reaches the next token. So when an error points at a line that looks fine, check the line before it. main.cpp:5:5 is file, line, then column. Fix the one thing it names and recompile - resist guessing.

Compiler errors mean nothing ran yet. They're different from runtime errors, where your program started and then crashed. Catching mistakes at compile time, before the program ever runs, is one of C++'s biggest strengths.

A Sanity-Check Program

Run this in the editor, or save it as main.cpp and do g++ -std=c++17 -Wall main.cpp -o main then ./main on your own machine. If all three lines appear, your toolchain works end to end:

Three things appear here that you'll meet properly soon: an int variable, a vector (C++'s resizable array), and cout for output. For now it's enough that the program compiles and prints all three lines in order.

Next: C++ Syntax

You've compiled and run a few programs, but we've been waving past the punctuation - the #include lines, the braces, the semicolons, int main(), and why every line looks the way it does. The next page breaks down C++ syntax piece by piece, so the structure stops feeling like boilerplate and starts making sense.

Frequently Asked Questions

How do I compile and run a C++ program?

Save your code as main.cpp, open a terminal in that folder, and run g++ main.cpp -o main to produce an executable. Then run it with ./main on macOS/Linux or main.exe on Windows. You compile once; you can run the resulting binary as many times as you like.

What does the -o flag do in g++?

-o names the output file. g++ main.cpp -o hello creates an executable called hello. Leave -o off and g++ defaults to a.out (or a.exe on Windows) - which is why beginners often end up running a file they didn't realize they made.

How do I compile C++ with a specific standard like C++17 or C++20?

Pass the -std flag: g++ -std=c++17 main.cpp -o main or -std=c++20. Without it, the compiler uses its own default, which may be older than you expect, so newer features like structured bindings or <ranges> may fail to compile until you set the standard explicitly.

Coddy programming languages illustration

Learn to code with Coddy

GET STARTED