Your first C++ program

The first program in every language prints a line, and it is worth reading this one slowly: eight lines of C++ contain a preprocessor directive, a function, a stream and a return value, and each of them comes back in every program of the course. Everything here is compiled and run with the commands shown.

Hello, world

Save the four lines as hello.cpp and compile them. The compiler reads the file, the linker adds the standard library, and the result is a file called hello that the system can run. Nothing is interpreted and no virtual machine is involved: the file contains machine code for this processor.

The program prints one line and ends. The newline is part of the string, so the terminal returns the cursor to the left edge before the shell prints its prompt; without it the prompt would sit at the end of the output.

#include <iostream> int main() { std::cout << "Hello, world!\n"; }

g++ -std=c++23 -Wall -Wextra hello.cpp -o hello
./hello

Hello, world!

The parts of the program

#include <iostream> asks the preprocessor to paste the declarations of the input and output streams into the file. std::cout is the standard output stream, << sends a value into it, and \n is the newline character. std:: is the namespace of the standard library, which keeps its names apart from yours.

int main() is the function the operating system calls. The int is the value the program returns to whoever started it, and the braces hold the statements. A program with no return statement returns 0, which means success.

The second line shows that << can be chained and repeated: each statement ends with a semicolon, and each string is printed where it stands in the statement.

#include <iostream> int main() { std::cout << "C++ writes to a stream, not to a screen\n"; std::cout << "the shell decides where the stream goes\n"; return 0; }

g++ -std=c++23 -Wall -Wextra parts.cpp -o parts
./parts

C++ writes to a stream, not to a screen
the shell decides where the stream goes

Preprocess, compile, link

g++ hides four steps behind one command. The preprocessor expands #include and macros, the compiler turns the result into assembly and then into an object file, and the linker joins object files and libraries into an executable. -c stops after the object file; the second command links that file by hand.

The preprocessed file is enormous because <iostream> pulls in the whole stream library: the command below counts the lines after preprocessing, and the answer is in the tens of thousands for a two line source. That is why the first compile of a file is slower than the next one.

Linking a single object file looks like extra work, and it is exactly what happens inside the one-line command. Lesson 006 splits a program into several object files, where the step becomes necessary.

#include <iostream> int main() { std::cout << "two steps: compile, then link\n"; }

g++ -std=c++23 -E stages.cpp | wc -l
g++ -std=c++23 -Wall -Wextra -c stages.cpp -o stages.o
g++ stages.o -o stages
./stages

65105
two steps: compile, then link

The exit status

main returns an int, and the shell keeps it as the exit status of the program. Zero means success and anything else means failure, which is how a build script, a test runner or a package manager decides whether the last command worked.

Bash stores the status in $?, and echo prints it. The program below returns 3 on purpose; the shell prints 3 after the program's own line.

The exit status is also what g++ reports: 0 for a clean build, 1 for a compile error. That single number is the contract between every command in a build pipeline.

#include <iostream> int main() { std::cout << "this program reports failure to the shell\n"; return 3; }

g++ -std=c++23 -Wall -Wextra exit_code.cpp -o exit_code
./exit_code; echo $?

this program reports failure to the shell
3

The first error you will meet

A missing semicolon is the most common first error in C++, and the message is about the token after the missing one. Here the statement ends after the string, the compiler keeps reading, and the closing brace of main arrives where it expected a semicolon.

The message names the line of the brace, not the line of the mistake. When a diagnostic points at a closing brace or at a line that looks correct, check the line above it: an unterminated statement, a missing parenthesis or a string that is not closed all look like this from the parser's side.

Adding the semicolon fixes it, and no other change is needed. The rest of the course will meet harder messages; the habit of reading the first error and the line above it starts here.

#include <iostream> int main() { std::cout << "Hello, world!\n" }

g++ -std=c++23 -Wall -Wextra semicolon.cpp -o semicolon

semicolon.cpp: In function 'int main()':
semicolon.cpp:5:35: error: expected ';' before '}' token
5 | std::cout << "Hello, world!\n"
| ^
| ;
6 | }
| ~

Exercises

  1. Print your name and the name of the compiler on two lines, then check the exit status with echo $?.
  2. Compile hello.cpp with -o hello and then rename the binary. Does the program still run, and does it know its own name?
  3. Remove the return 0 from main and run the program. What exit status does the shell report, and why?

Questions

A new set of questions in a new order every time. Choose one answer for each, then check.

  1. What does #include <iostream> bring into the file?

    Answer

    The declarations of the input and output streams

    The header declares std::cout and its friends; the implementation is in the library the linker adds.

  2. What does std::cout << text do?

    Answer

    It writes the text to the standard output stream

    The stream is an object, and the operator sends characters into it; the shell decides where they arrive.

  3. What does return 0; at the end of main mean?

    Answer

    The program reports success to the shell

    The return value of main becomes the exit status, and zero is the conventional success.

  4. What does g++ -c stages.cpp -o stages.o do?

    Answer

    It compiles the source to an object file without linking

    The -c flag stops after compilation, which is the first half of the two-step build.

  5. What does this program print? #include <iostream> int main() { std::cout << "Hello" << ", " << "world" << '!'; }

    Answer

    Hello, world!

    The three pieces are written to the same stream in order, and the line has no trailing newline.

  6. What does this program report to the shell? int main() { return 3; }

    Answer

    3

    The return value of main becomes the exit status, and 3 is what the shell reads.

  7. A program's main ends with return 3;. What exit status does the shell receive?

    Answer

    3

    The return value of main becomes the exit status, and 3 is what the shell reads.

  8. What does g++ -std=c++23 -E stages.cpp | wc -l print?

    Answer

    65105

    The preprocessor output includes all the headers, and the line count is the size of that text on this build.

  9. What does the compiler say about the missing semicolon?

    Answer

    expected ';' before '}' token

    The statement ends at the closing brace, and the compiler asks for the semicolon before it.

  10. Why build in two steps, compile and then link?

    Answer

    So a change to one source recompiles only that object

    Separate objects are the unit a build system can reuse, which is what the rest of the course relies on.

The code on this page was run with g++ 15.2.0 on Alpine Linux 3.24.3 (x86_64) in a Docker container.

Article author: Arthur Isaev