C++ Compilar com g++
Na aula anterior você compilou com o comando mais curto possível, g++ ola.cpp -o ola. Ele funciona, mas deixa o compilador no "modo de fábrica": usando uma versão antiga do C++ e calado sobre muitos erros prováveis. Nesta aula você monta, peça por peça, o comando que o guia usa em todas as aulas daqui para a frente, e aprende a compilar e rodar numa linha só.
- O comando padrão do guia:
g++ -std=c++23 -Wall -Wextra ola.cpp -o ola. - O que fazem
-std,-Wall,-Wextrae-o, e para que servem-ge-O2. - Por que o
std::printlndá erro sem-std=c++23. - Compilar e rodar numa linha com
&&. - Por que é preciso recompilar depois de editar o código.
- Como usar o
clang++, o outro grande compilador, no lugar dog++.
Todos os comandos foram executados na máquina da Ana com o g++ 15.2 e o clang++ 21.1 do Ubuntu 26.04, na pasta ~/cpp, com o ola.cpp da aula Olá, Mundo.
A ideia: os botões do forno
Voltando à cozinha da aula anterior: o compilador é a cozinheira, e o código é a receita. Mas a cozinheira também precisa saber como trabalhar. "Use a receita nova, não a da vovó." "Me avise se algum ingrediente parecer estragado." "Capriche, que é para festa." Essas instruções extras são as opções do compilador: palavras que começam com - (hífen) e mudam o jeito como ele trabalha, sem mudar o código.
1. O comando padrão do guia
Este é o comando que você vai digitar em quase todas as aulas:
- g++
- O compilador de C++ do projeto GNU.
- -std=c++23
- "Use o C++23", a versão da linguagem que o guia ensina. Seção 2.
- -Wall
- "Avise sobre tudo o que é suspeito" (Warnings: all). Seção 3.
- -Wextra
- "E mais alguns avisos extras." Seção 3.
- ola.cpp
- O arquivo de código.
- -o ola
- O nome do programa que será criado. Seção 4.
$ g++ -std=c++23 -Wall -Wextra ola.cpp -o ola $ ./ola Olá, mundo!
O resultado é o mesmo de antes, porque o ola.cpp é simples e não tem nada de errado. A diferença aparece quando o código usa recursos novos ou tem problemas escondidos, como você vai ver a seguir.
As opções podem vir em qualquer ordem: g++ ola.cpp -Wextra -o ola -std=c++23 -Wall funciona igual. A única regra é que o nome do programa vem logo depois do -o. O guia usa sempre a mesma ordem, para você se acostumar.
2. -std=c++23: qual C++ usar
O C++ ganha uma versão nova a cada três anos: C++11, C++14, C++17, C++20, C++23 (veja Versões do C++). Cada uma traz recursos novos. O -std (de standard, "padrão") diz ao compilador qual versão seguir.
E se você não disser? O g++ 15 usa o C++17, de 2017. Dá para conferir: todo compilador define um número especial, __cplusplus, com o ano e o mês da versão em uso. Este programa só mostra esse número:
#include <iostream>
int main() {
std::cout << __cplusplus << "\n";
}
$ g++ versao.cpp -o versao && ./versao 201703 « sem -std: C++17 (2017, mês 03) $ g++ -std=c++20 versao.cpp -o versao && ./versao 202002 « C++20 $ g++ -std=c++23 versao.cpp -o versao && ./versao 202302 « C++23: o que o guia usa $ g++ -std=c++26 versao.cpp -o versao && ./versao 202400 « C++26: ainda em acabamento, por isso o número "provisório"
(O && entre os dois comandos é explicado na seção 5.)
O que acontece sem -std=c++23
O C++23 trouxe o std::println, um jeito mais simples de mostrar texto (aula std::format e std::print). Veja o que acontece ao compilar um programa com ele sem pedir o C++23:
#include <print>
int main() {
std::println("Olá, {}!", "Ana");
}
$ g++ println.cpp -o println
println.cpp: In function ‘int main()’:
println.cpp:4:10: error: ‘println’ is not a member of ‘std’
4 | std::println("Olá, {}!", "Ana");
| ^~~~~~~
println.cpp:4:10: note: ‘std::println’ is only available from C++23 onwards
$ g++ -std=c++23 println.cpp -o println && ./println
Olá, Ana!
A primeira mensagem diz "println não é membro de std": o compilador, no modo C++17, não conhece esse nome. A note (nota) logo abaixo é a dica preciosa: "std::println só está disponível a partir do C++23". Com -std=c++23, o mesmo arquivo compila e roda.
c++23 ou gnu++23?
Você pode encontrar -std=gnu++23. É o C++23 mais algumas extensões próprias do GNU, que não existem nos outros compiladores. Na verdade, o padrão de fábrica do g++ 15 é o gnu++17. O guia usa c++23 (sem extensões) para o seu código funcionar em qualquer compilador.
O editor do guia já compila com -std=c++23. Experimente ver o número da versão e o std::println funcionando:
Missão: rode e confira o número da versão. Depois acrescente, antes da }, uma linha com std::println("Olá, {}!", "Ana"); e rode de novo. (O #include <print> já está lá.)
#include <iostream>
#include <print>
int main() {
std::cout << __cplusplus << "\n";
}
#include <iostream>
#include <print>
int main() {
std::cout << __cplusplus << "\n";
std::println("Olá, {}!", "Ana");
}
3. -Wall e -Wextra: peça para ser avisado
O compilador encontra dois tipos de problema:
- Erros (
error:): o código não segue as regras do C++. O programa não é criado. - Avisos (
warning:): o código segue as regras, mas tem cara de engano. O programa é criado, e o compilador só comenta: "tem certeza?".
No modo de fábrica, o g++ mostra pouquíssimos avisos. As opções que começam com -W (de warning, "aviso") ligam grupos deles. Veja este programa, em que a Ana criou uma variável itens e esqueceu de usá-la (variáveis são o assunto de Variáveis; aqui basta saber que int itens = 3; guarda o número 3 com o nome itens):
#include <iostream>
int main() {
int itens = 3;
std::cout << "Lista de compras da Ana\n";
}
$ g++ compras.cpp -o compras
$ « nenhuma palavra
$ g++ -Wall compras.cpp -o compras
compras.cpp: In function ‘int main()’:
compras.cpp:4:9: warning: unused variable ‘itens’ [-Wunused-variable]
4 | int itens = 3;
| ^~~~~
Com -Wall, o g++ avisou: "variável não usada: itens". Não é um erro (o programa foi criado), mas é uma pista: ou a variável sobrou, ou você esqueceu de mostrá-la. Entre colchetes, [-Wunused-variable] é o nome do aviso, que você pode pesquisar.
Apesar do nome, -Wall ("todos") não liga todos os avisos. O -Wextra acrescenta outros. Um exemplo: uma main que declara que recebe os argumentos da linha de comando (as palavras digitadas depois do nome do programa; os parâmetros são explicados em Parâmetros e Argumentos) mas não usa nenhum:
#include <iostream>
int main(int argc, char* argv[]) {
std::cout << "Olá!\n";
}
$ g++ -Wall args.cpp -o args
$ « o -Wall sozinho não viu nada
$ g++ -Wall -Wextra args.cpp -o args
args.cpp: In function ‘int main(int, char**)’:
args.cpp:3:14: warning: unused parameter ‘argc’ [-Wunused-parameter]
3 | int main(int argc, char* argv[]) {
| ~~~~^~~~
args.cpp:3:26: warning: unused parameter ‘argv’ [-Wunused-parameter]
3 | int main(int argc, char* argv[]) {
| ~~~~~~^~~~~~
Os avisos têm aula própria, com os casos que realmente salvam programas (comparações que dão resultado errado, variáveis sem valor, = no lugar de ==): Avisos (-Wall -Wextra). Por enquanto, a regra é simples: compile sempre com -Wall -Wextra, e trate cada aviso como um erro a corrigir.
-Wall tem W maiúsculo. Com minúsculo, o g++ não reconhece a opção, mas pelo menos sugere a certa:
$ g++ -std=c++23 -wall ola.cpp -o ola g++: error: unrecognized command-line option ‘-wall’; did you mean ‘-Wall’? $ g++ -std=c+23 ola.cpp -o ola g++: error: unrecognized command-line option ‘-std=c+23’; did you mean ‘-std=c++23’?
"Opção de linha de comando não reconhecida; você quis dizer…?" Leia a sugestão e corrija.
4. -o: o nome do programa
Você já conhece: -o ola cria o programa ola; sem -o, o nome é a.out (aula Olá, Mundo). Dois detalhes:
- Se já existir um programa com esse nome, ele é substituído sem perguntar. É o que você quer quando recompila.
- O nome depois de
-onunca deve ser o do arquivo.cpp. O g++ 15 recusa (input file ‘ola.cpp’ is the same as output file), mas não conte com isso para outros arquivos.
5. Compilar e rodar numa linha: &&
Você vai compilar e rodar centenas de vezes. Para não digitar dois comandos, junte-os com && ("e então"):
$ g++ -std=c++23 -Wall -Wextra ola.cpp -o ola && ./ola Olá, mundo!
O && é do terminal, não do C++: ele roda o segundo comando só se o primeiro der certo. Se a compilação falhar, o programa não roda. Isso é exatamente o que você quer, como mostra a próxima seção.
No terminal, a seta para cima traz de volta o último comando. O ciclo de trabalho vira: editar, salvar, ir ao terminal, ↑, Enter.
6. Mudou o código? Compile de novo
Lembra do bolo? Se você muda a receita, o bolo que já está pronto não muda sozinho. O programa ola é uma "foto" do ola.cpp no momento em que foi compilado. Veja: a Ana troca mundo por Ana no ola.cpp, salva, e roda o programa sem compilar:
#include <iostream>
int main() {
std::cout << "Olá, Ana!\n";
}
$ ./ola Olá, mundo! « o programa antigo! ninguém o recompilou $ g++ -std=c++23 -Wall -Wextra ola.cpp -o ola $ ./ola Olá, Ana! « agora sim
É um dos sustos mais comuns: "eu mudei o código e nada mudou!". Antes de procurar o erro, pergunte-se: salvei o arquivo? Recompilei?
Por que o && protege você
Agora a Ana troca para Bruno, mas esquece o ;. Com &&:
$ g++ -std=c++23 -Wall -Wextra ola.cpp -o ola && ./ola
ola.cpp: In function ‘int main()’:
ola.cpp:4:33: error: expected ‘;’ before ‘}’ token
4 | std::cout << "Olá, Bruno!\n"
| ^
| ;
5 | }
| ~
A compilação falhou, o ./ola não rodou, e a tela mostra só o erro. Agora compare com ; (ponto e vírgula do terminal, que roda o segundo comando sempre):
$ g++ -std=c++23 -Wall -Wextra ola.cpp -o ola ; ./ola
ola.cpp: In function ‘int main()’:
ola.cpp:4:33: error: expected ‘;’ before ‘}’ token
4 | std::cout << "Olá, Bruno!\n"
| ^
| ;
5 | }
| ~
Olá, Ana! « o programa ANTIGO rodou, e parece que deu tudo certo
Quando a compilação falha, o g++ não mexe no programa que já existia. Com ;, o terminal roda esse programa velho, e a última linha da tela engana: parece que funcionou. Use sempre &&.
7. Duas opções para depois: -g e -O2
Você não vai precisar delas agora, mas vai encontrá-las em todo lugar.
-g: informações para depurar
O -g guarda dentro do programa um "mapa" que liga cada pedaço do programa à linha do código-fonte. Ele não muda o que o programa faz; só permite que um depurador como o gdb mostre "parei na linha 4" e o valor das variáveis (aula Depurar com o GDB). O preço é um arquivo maior:
-O2: otimizar
-O (letra O maiúscula, de optimize) seguido de um nível: -O0 (nenhuma otimização, o padrão), -O1, -O2, -O3. Com -O2, o compilador gasta mais tempo procurando jeitos de o programa rodar mais rápido: reorganiza contas, elimina trabalho repetido. É o nível usado na maioria dos programas que vão para os usuários.
$ g++ -std=c++23 -Wall -Wextra ola.cpp -o ola $ g++ -std=c++23 -Wall -Wextra -g ola.cpp -o ola-debug $ g++ -std=c++23 -Wall -Wextra -O2 ola.cpp -o ola-rapido $ ls -l ola ola-debug ola-rapido -rwxrwxr-x 1 ana ana 16120 out 16 21:41 ola -rwxrwxr-x 1 ana ana 50080 out 16 21:41 ola-debug « o -g triplicou o tamanho: é o "mapa" -rwxrwxr-x 1 ana ana 16144 out 16 21:41 ola-rapido
Num Olá, mundo não há o que acelerar. Num programa que faz muita conta, a diferença aparece. Este faz 300 milhões de somas (não se preocupe com o for, que é da aula for; o time do terminal mede quanto tempo o programa levou):
#include <iostream>
int main() {
long long soma = 0;
for (long long i = 1; i <= 300000000; i++) {
soma = soma + i % 7;
}
std::cout << "Soma: " << soma << "\n";
}
$ g++ -std=c++23 -Wall -Wextra soma.cpp -o soma $ time ./soma Soma: 900000003 real 0m1,079s « sem otimização: pouco mais de 1 segundo user 0m1,078s sys 0m0,001s $ g++ -std=c++23 -Wall -Wextra -O2 soma.cpp -o soma $ time ./soma Soma: 900000003 real 0m0,493s « com -O2: menos da metade do tempo, mesmo resultado user 0m0,490s sys 0m0,002s
Enquanto aprende, compile sem -O2 e, para depurar, com -g: o programa otimizado fica tão reorganizado que o depurador não consegue mais seguir as linhas. O -O2 tem um bônus: ele faz o g++ analisar o código mais a fundo e, por isso, achar alguns avisos a mais (aula Avisos).
8. A alternativa: clang++
O g++ não é o único compilador de C++. O outro grande é o Clang (comando clang++), do projeto LLVM, usado pela Apple no macOS e por muitas empresas. Ele aceita as mesmas opções:
$ clang++ --version Ubuntu clang version 21.1.8 (6ubuntu1) Target: x86_64-pc-linux-gnu Thread model: posix InstalledDir: /usr/lib/llvm-21/bin $ clang++ -std=c++23 -Wall -Wextra ola.cpp -o ola && ./ola Olá, mundo!
No Ubuntu, ele vem no pacote clang (Instalar no Linux). As mensagens de erro dizem a mesma coisa que as do g++, com outras palavras. Veja o std::println sem -std=c++23 (o Clang 21 também usa C++17 se você não pedir outro):
$ clang++ println.cpp -o println
println.cpp:4:10: error: no member named 'println' in namespace 'std'
4 | std::println("Olá, {}!", "Ana");
| ^~~~~~~
1 error generated.
$ clang++ -std=c++23 println.cpp -o println && ./println
Olá, Ana!
"Nenhum membro chamado println no namespace std": o mesmo erro do g++, sem a nota sobre o C++23. Saber ler os dois é útil, porque o editor do guia usa o Clang (compilado para rodar no navegador), enquanto os exemplos de terminal usam o g++. Comparações lado a lado dos dois estão em Lendo Erros do Compilador.
| g++ (GCC) | clang++ (LLVM) | |
|---|---|---|
| Quem faz | Projeto GNU | Projeto LLVM |
| Onde é o padrão | Linux | macOS (e o editor deste guia) |
| Opções | As mesmas para o dia a dia: -std=c++23 -Wall -Wextra -o -g -O2 | |
| Mensagens | Aspas tipográficas ‘assim’, notas longas | Aspas simples 'assim', terminam com "N errors generated." |
Qual usar? Qualquer um. O guia mostra o g++ porque é o que vem no Ubuntu. Compilar o mesmo código com os dois é um bom teste: se os dois aceitam sem avisos, o seu código provavelmente segue o padrão à risca.
Quando dá errado
error: ‘println’ is not a member of ‘std’
O que significa: você usou um recurso de uma versão mais nova do C++ sem o -std correspondente. A note logo abaixo costuma dizer a versão (only available from C++23 onwards). Também acontece quando falta o #include (aqui, #include <print>).
Como consertar: compile com -std=c++23 e confira o #include.
g++: error: unrecognized command-line option
O que significa: uma opção foi digitada errado: -wall, -std=c+23, -Wextras. O g++ costuma sugerir a certa (did you mean …?).
Como consertar: copie a sugestão. Maiúsculas e minúsculas importam.
O que significa: você está rodando o programa antigo. Ou o arquivo não foi salvo, ou não foi recompilado, ou a compilação falhou e você rodou o programa velho (com ; em vez de &&, ou rodando ./ola sem ler o erro).
Como consertar: salve, compile com g++ … && ./ola e leia tudo o que aparecer antes da saída do programa.
O que significa: avisos não impedem a criação do programa. Mas eles quase sempre apontam um engano real.
Como consertar: leia cada warning: e corrija o código até a compilação ficar em silêncio. A aula Avisos mostra os mais comuns.
Referência rápida
| Opção | O que faz | Quando usar |
|---|---|---|
-std=c++23 | Segue o C++23 (sem ela, o g++ 15 usa C++17) | Sempre, neste guia |
-Wall | Liga os avisos mais importantes | Sempre |
-Wextra | Liga avisos extras | Sempre |
-o nome | Nome do programa criado (sem ela: a.out) | Sempre |
-g | Guarda informações para o depurador | Ao depurar (GDB) |
-O2 | Otimiza: programa mais rápido, compilação mais lenta | Na versão final; para achar mais avisos |
-Werror | Transforma avisos em erros | Projetos sérios (Avisos) |
cmd1 && cmd2 | Roda cmd2 só se cmd1 deu certo | Compilar e rodar: g++ … && ./ola |
clang++ | O compilador Clang, com as mesmas opções | Alternativa ao g++ |
Outras opções que você vai conhecer mais adiante: -c e vários arquivos (Compilar Vários Arquivos), -fsanitize (Sanitizers), -I e -l (Usar Bibliotecas Externas). Quando os comandos ficarem compridos, ferramentas como Make e CMake digitam por você.
Exercícios
1. A versão
Complete o comando para compilar seguindo o C++23:
2. Compilar e rodar
Complete para rodar o ./jogo só se a compilação der certo:
3. Depurar
Qual opção guarda no programa as informações que o gdb usa?
4. Você editou e salvou o jogo.cpp, rodou ./jogo e viu a saída antiga. Por quê?
5. Sem nenhum -std, qual versão do C++ o g++ 15 segue?
6. O que acontece com um programa que gerou só avisos (warning:), sem erros?
Missão final: o recado em C++23
Missão: o editor compila como o comando padrão do guia (-std=c++23 -Wall -Wextra). Este programa compila, mas com um aviso. Faça três coisas: (1) rode e leia o aviso; (2) apague a linha que o causa; (3) troque o std::cout por std::println, que já quebra a linha sozinho (por isso, sem o \n), e acrescente uma segunda linha: 1 kg de arroz.
#include <iostream>
#include <print>
int main() {
int itens = 3;
std::cout << "Lista de compras da Ana\n";
}
#include <iostream>
#include <print>
int main() {
std::println("Lista de compras da Ana");
std::println("1 kg de arroz");
}
Resumo
- Comando padrão do guia:
g++ -std=c++23 -Wall -Wextra arquivo.cpp -o programa. -std=c++23escolhe a versão; sem ele, o g++ 15 usa C++17 e não conhece ostd::println.-Wall -Wextraligam os avisos: o programa é criado, mas o compilador aponta enganos prováveis.-gserve ao depurador;-O2deixa o programa mais rápido.g++ … && ./programacompila e roda, e não roda nada se a compilação falhar.- Mudou o código? Salve e recompile. O programa antigo não muda sozinho.
clang++aceita as mesmas opções; o editor do guia usa o Clang.