Compile, depois rode
Agora que você tem um compilador instalado, fazer um programa em C++ rodar é um ciclo de duas etapas. Diferente de uma linguagem de script, em que um interpretador lê seu arquivo linha por linha, o C++ primeiro compila seu código-fonte em um executável nativo (um binário independente de código de máquina) e depois você roda esse binário diretamente. Não há nenhum interpretador entre o seu programa e a CPU em tempo de execução.
Essa separação é o motivo de o C++ ser rápido, e também o motivo de um erro de sintaxe te parar em tempo de compilação em vez de no meio de uma execução. O compilador verifica o arquivo inteiro antes de produzir qualquer coisa.
Você pode rodar qualquer exemplo autocontido aqui mesmo na página - o editor abaixo compila e roda para você. Mas vale a pena saber o que acontece na sua própria máquina, porque é lá que os projetos de verdade vivem.
O ciclo de compilar e rodar na sua máquina
Digamos que você salvou isto como main.cpp:
#include <iostream>
using namespace std;
int main() {
cout << "Hello from the terminal" << endl;
return 0;
}
Abra um terminal na pasta que contém o arquivo e invoque o compilador. O compilador mais comum é o g++ (parte do GCC); o clang++ funciona de forma idêntica para tudo aqui:
g++ main.cpp -o main
Se o código compila sem problemas, o g++ não imprime nada e cria um arquivo novo ao lado do seu fonte: um executável chamado main (ou main.exe no Windows). Esse binário é código de máquina - não é texto legível, e está atrelado ao seu sistema operacional e à sua CPU. Agora rode-o:
./main
Hello from the terminal
No Windows você o rodaria como main.exe (ou só main) a partir do mesmo terminal. O ./ no macOS e no Linux diz ao shell "o programa está bem aqui, nesta pasta, não em algum lugar do PATH" - um passo que iniciantes esquecem e depois se perguntam por que main diz command not found.
O que o -o faz (e o a.out)
A flag -o dá nome à saída. Se você a omite, o g++ ainda compila, mas grava o executável com um nome padrão: a.out no macOS/Linux, a.exe no Windows.
g++ main.cpp # produces a.out, not main
./a.out
Isso confunde as pessoas o tempo todo: elas compilam, não veem erros, rodam ./main e recebem No such file or directory - porque o binário na verdade se chama a.out. Sempre passe -o para saber exatamente o que está rodando.
Você compila uma vez a cada mudança no código-fonte. Depois disso, o executável é independente - você pode rodar ./main cem vezes sem recompilar. Você só roda o g++ de novo depois de editar o arquivo .cpp.
Escolhendo um padrão de C++
O C++ tem versões - C++11, C++14, C++17, C++20, C++23 - cada uma adicionando recursos à linguagem. O detalhe: seu compilador escolhe um padrão default que pode ser mais antigo do que você espera, então código moderno pode não compilar sem motivo aparente. Defina o padrão explicitamente com -std:
g++ -std=c++17 main.cpp -o main
g++ -std=c++20 main.cpp -o main
Aqui está um código que usa um recurso do C++17 (structured bindings). Ele compila bem no editor, mas na sua máquina precisa de -std=c++17 ou mais novo:
Se você um dia vir um erro como 'structured bindings' only available with '-std=c++17', a correção não está no seu código - está em adicionar a flag -std certa. Ao longo deste curso, assuma C++17 ou mais novo.
Ligue os avisos
Um programa em C++ pode compilar sem problemas e ainda assim estar errado. O compilador, se você pedir, vai apontar código suspeito antes que ele te morda em tempo de execução. Adicione -Wall -Wextra:
g++ -std=c++17 -Wall -Wextra main.cpp -o main
Considere este programa. Ele compila sem -Wall, mas tem um bug de verdade - ler uma variável que nunca recebeu um valor, o que é comportamento indefinido:
#include <iostream>
using namespace std;
int main() {
int count; // never initialized
cout << count << endl; // reads garbage - undefined behavior
return 0;
}
Com os avisos ligados, o compilador o sinaliza:
warning: 'count' is used uninitialized [-Wuninitialized]
Crie o hábito de compilar com -Wall -Wextra desde o primeiro dia. Os avisos são o compilador fazendo uma revisão de código de graça; ignorá-los é como bugs sutis sobrevivem. A correção aqui é simplesmente int count = 0;.
Lendo os erros do compilador
Quando o g++ rejeita seu código, ele aponta o arquivo, a linha e o que deu errado. Aprender a ler essas mensagens é metade do caminho para se desenrolar. Aqui está o clássico - um ponto e vírgula faltando:
#include <iostream>
using namespace std;
int main() {
cout << "Oops" // no semicolon
return 0;
}
main.cpp:5:5: error: expected ';' before 'return'
5 | return 0;
| ^~~~~~
Algumas coisas para notar. O erro reporta a linha 5, mas o erro está na linha 4 - o compilador só percebe que falta um ponto e vírgula quando chega ao próximo token. Então, quando um erro aponta para uma linha que parece certa, verifique a linha anterior. main.cpp:5:5 é arquivo, linha e depois coluna. Corrija a única coisa que ele nomeia e recompile - resista a chutar.
Erros do compilador significam que nada rodou ainda. Eles são diferentes dos erros em tempo de execução, em que o programa começou a rodar e depois travou. Pegar erros em tempo de compilação, antes de o programa sequer rodar, é uma das maiores forças do C++.
Um programa de verificação
Rode isto no editor, ou salve como main.cpp e faça g++ -std=c++17 -Wall main.cpp -o main e depois ./main na sua própria máquina. Se as três linhas aparecerem, sua cadeia de ferramentas funciona de ponta a ponta:
Três coisas aparecem aqui que você vai conhecer direito em breve: uma variável int, um vector (o array redimensionável do C++) e o cout para a saída. Por enquanto basta que o programa compile e imprima as três linhas em ordem.
Próximo: Sintaxe de C++
Você compilou e rodou alguns programas, mas passamos por cima da pontuação - as linhas #include, as chaves, os pontos e vírgulas, o int main() e por que cada linha tem a aparência que tem. A próxima página destrincha a sintaxe de C++ peça por peça, para que a estrutura deixe de parecer código padrão e comece a fazer sentido.
Perguntas frequentes
Como eu compilo e rodo um programa em C++?
Salve seu código como main.cpp, abra um terminal nessa pasta e rode g++ main.cpp -o main para gerar um executável. Depois, rode-o com ./main no macOS/Linux ou main.exe no Windows. Você compila uma vez; pode rodar o binário resultante quantas vezes quiser.
O que a flag -o faz no g++?
-o dá nome ao arquivo de saída. g++ main.cpp -o hello cria um executável chamado hello. Sem -o, o g++ usa o nome padrão a.out (ou a.exe no Windows) - por isso iniciantes muitas vezes acabam rodando um arquivo que nem sabiam que tinham criado.
Como compilo C++ com um padrão específico, como C++17 ou C++20?
Passe a flag -std: g++ -std=c++17 main.cpp -o main ou -std=c++20. Sem ela, o compilador usa o próprio padrão, que pode ser mais antigo do que você espera, então recursos mais novos como structured bindings ou <ranges> podem não compilar até você definir o padrão explicitamente.