C++ Mensagens de Erro
O compilador de C++ é exigente e fala inglês. Quando algo dá errado, ele escreve o arquivo, a linha, a coluna e uma frase curta, às vezes seguida de dezenas de linhas de "notas". Esta página junta as mensagens que você mais vai encontrar: de compilação, de ligação e de execução. Cada uma vem com o código que a provoca, o que ela quer dizer, como consertar e a aula onde o assunto é explicado. Todas foram provocadas de verdade no g++ 15.2 e no clang++ 21 da máquina da Ana.
- Copie um pedaço da mensagem que apareceu para você (por exemplo,
was not declared) e procure aqui com Ctrl+F. - Os programas ficam na pasta
~/errosda Ana. No seu computador, o nome do arquivo e o número da linha serão outros; o texto da mensagem é o mesmo. - As mensagens do g++ saem em inglês, com aspas tipográficas ‘assim’. As do ligador (
ld) e do terminal saem em português na máquina da Ana, porque esses programas têm tradução instalada; a versão em inglês aparece logo ao lado. - O editor do guia usa o Clang, não o g++. Por isso, os 10 erros mais comuns têm as duas versões lado a lado. Veja também O Editor do Guia.
- Todos os programas foram compilados com o comando padrão do guia:
g++ -std=c++23 -Wall -Wextra arquivo.cpp -o programa(veja Compilar com g++).
Atalhos: Ler uma mensagem · Compilação, ligação ou execução? · Os 10 mais comuns (g++ × clang++) · Outros erros de compilação · Mensagens gigantes · Avisos · Erros de ligação · Erros de execução · Códigos de saída · Sanitizers
Como ler uma mensagem do g++
A Ana escreveu um programa para a lojinha com três descuidos: esqueceu um ;, esqueceu o std:: e digitou um nome errado.
#include <iostream>
int main() {
int preco = 10
int quantidade = 3;
cout << "Total: " << preco * quantidade << '\n';
std::cout << "Itens: " << quantdade << '\n';
}
$ g++ -std=c++23 -Wall -Wextra loja.cpp -o loja
loja.cpp: In function ‘int main()’:
loja.cpp:5:5: error: expected ‘,’ or ‘;’ before ‘int’
5 | int quantidade = 3;
| ^~~
loja.cpp:6:5: error: ‘cout’ was not declared in this scope; did you mean ‘std::cout’?
6 | cout << "Total: " << preco * quantidade << '\n';
| ^~~~
| std::cout
In file included from loja.cpp:1:
/usr/include/c++/15/iostream:65:18: note: ‘std::cout’ declared here
65 | extern ostream cout; ///< Linked to standard output
| ^~~~
loja.cpp:6:34: error: ‘quantidade’ was not declared in this scope
6 | cout << "Total: " << preco * quantidade << '\n';
| ^~~~~~~~~~
loja.cpp:7:31: error: ‘quantdade’ was not declared in this scope
7 | std::cout << "Itens: " << quantdade << '\n';
| ^~~~~~~~~
$ echo $?
1
| Pedaço | O que quer dizer |
|---|---|
loja.cpp: In function ‘int main()’: | Contexto: "dentro da função main". Não é um erro; diz onde estão os próximos. |
loja.cpp:5:5: | Arquivo:linha:coluna. Linha 5, coluna 5. Seu editor pula direto para lá. |
error: | O tipo: error impede o programa de ser criado; warning (aviso) deixa criar, mas avisa de algo suspeito; note (nota) é uma informação extra sobre a mensagem anterior. |
expected ‘,’ or ‘;’ before ‘int’ | O texto: "esperava , ou ; antes de int". O erro está no fim da linha 4, mas o compilador só percebe na linha 5, quando encontra o int. |
5 | int quantidade = 3; | ^~~ | A linha do código, com o ^ apontando a coluna e os ~ sublinhando o trecho. |
| std::cout | Uma sugestão de conserto, escrita embaixo do trecho. |
In file included from …note: ‘std::cout’ declared here | Uma nota apontando para dentro da biblioteca, só para mostrar onde o std::cout existe. Você não mexe nesse arquivo. |
[-Wunused-variable], [-fpermissive] | No fim de algumas mensagens: o nome da opção ligada a ela. [-Wxxx] é o nome do aviso (veja Avisos). [-fpermissive] quer dizer que uma opção antiga transformaria o erro em aviso: não use, conserte o código. |
Repare no terceiro erro: ‘quantidade’ was not declared. Mas a variável está declarada na linha 5! Por causa do ; que faltou, o compilador entendeu as linhas 4 e 5 como uma coisa só e "perdeu" a declaração. Um erro costuma provocar outros, em cascata. Por isso: leia o primeiro, conserte, compile de novo. A aula Lendo Erros do Compilador treina isso com calma.
Missão: este é o programa da lojinha. Clique em Rodar, leia as mensagens (aqui elas vêm do Clang, com outras palavras) e conserte os três erros até aparecer Total: 30 e Itens: 3.
#include <iostream>
int main() {
int preco = 10
int quantidade = 3;
cout << "Total: " << preco * quantidade << '\n';
std::cout << "Itens: " << quantdade << '\n';
}
#include <iostream>
int main() {
int preco = 10;
int quantidade = 3;
std::cout << "Total: " << preco * quantidade << '\n';
std::cout << "Itens: " << quantidade << '\n';
}
Compilação, ligação ou execução?
Um programa C++ passa por etapas (veja Como o C++ Vira Programa), e cada etapa tem o seu jeito de reclamar. Saber em qual etapa o erro aconteceu já diz metade da solução.
| Etapa | Como a mensagem começa | O que aconteceu | Seção |
|---|---|---|---|
| Compilação | arquivo.cpp:5:5: error: … | O compilador não entendeu o código ou achou um erro de tipo. Nenhum programa é criado. | Os 10 mais comuns, outros |
| Compilação (aviso) | arquivo.cpp:2:9: warning: … | O programa foi criado, mas há algo suspeito. Quase sempre é um defeito de verdade. | Avisos |
| Ligação | /usr/bin/x86_64-linux-gnu-ld.bfd: …collect2: error: ld returned 1 exit status | Cada arquivo compilou, mas, na hora de juntar as peças, falta uma (ou sobra uma repetida). | Ligação |
| Execução | Falha de segmentação, terminate called after throwing…, Abortado | O programa foi criado e rodou, mas morreu no meio. | Execução |
Os 10 erros mais comuns: g++ × clang++
A primeira linha de cada mensagem, nos dois compiladores. O editor do guia mostra a coluna do clang++. Abaixo da tabela, cada um em detalhe.
| # | Causa | g++ 15 | clang++ 21 (editor do guia) |
|---|---|---|---|
| 1 | Faltou o ; | error: expected ‘;’ before ‘}’ tokenerror: expected ‘,’ or ‘;’ before ‘std’ | error: expected ';' after expressionerror: expected ';' at end of declaration |
| 2 | Nome não declarado (ou digitado errado) | error: ‘totl’ was not declared in this scope; did you mean ‘total’? | error: use of undeclared identifier 'totl'; did you mean 'total'? |
| 3 | Esqueceu o std:: | error: ‘cout’ was not declared in this scope; did you mean ‘std::cout’?error: ‘string’ was not declared in this scope | error: use of undeclared identifier 'cout'; did you mean 'std::cout'?error: unknown type name 'string'; did you mean 'std::string'? |
| 4 | Faltou um #include | error: ‘setw’ is not a member of ‘std’+ note: ‘std::setw’ is defined in header ‘<iomanip>’ | error: no member named 'setw' in namespace 'std' (e às vezes uma sugestão sem sentido) |
| 5 | Nome do #include errado | fatal error: iostrem: Arquivo ou diretório inexistente | fatal error: 'iostrem' file not found |
| 6 | Valor de um tipo onde se espera outro | error: invalid conversion from ‘const char*’ to ‘int’ [-fpermissive] | error: cannot initialize a variable of type 'int' with an lvalue of type 'const char[3]' |
| 7 | cout << de algo que ele não sabe mostrar | error: no match for ‘operator<<’ (operand types are ‘std::ostream’ … and ‘std::vector<int>’) | error: invalid operands to binary expression ('ostream' … and 'std::vector<int>') |
| 8 | Número errado de argumentos | error: too few arguments to function ‘int soma(int, int)’ | error: no matching function for call to 'soma' |
| 9 | Mudar uma constante | error: assignment of read-only variable ‘maximo’ | error: cannot assign to variable 'maximo' with const-qualified type 'const int' |
| 10 | Faltou fechar uma } | error: expected ‘}’ at end of input | error: expected '}' |
| + | Função declarada, mas não definida (ligação) | referência não definida para "soma(int, int)"(em inglês: undefined reference to `soma(int, int)')collect2: error: ld returned 1 exit status | a mesma do ld, e no fim:clang++: error: linker command failed with exit code 1 (use -v to see invocation) |
expected ‘;’ before … — faltou o ponto e vírgula
#include <iostream>
int main() {
std::cout << "Olá" << '\n'
}
$ g++ -std=c++23 -Wall -Wextra pontovirgula2.cpp -o pontovirgula2
pontovirgula2.cpp: In function ‘int main()’:
pontovirgula2.cpp:4:31: error: expected ‘;’ before ‘}’ token
4 | std::cout << "Olá" << '\n'
| ^
| ;
5 | }
| ~
$ clang++ -std=c++23 -Wall -Wextra pontovirgula2.cpp -o pontovirgula2
pontovirgula2.cpp:4:32: error: expected ';' after expression
4 | std::cout << "Olá" << '\n'
| ^
| ;
1 error generated.
Quando falta o ; numa declaração (int idade = 30), o g++ escreve expected ‘,’ or ‘;’ before ‘std’ (com a palavra que veio depois) e o clang++, expected ';' at end of declaration.
Como consertar: o g++ aponta o lugar onde percebeu a falta, que muitas vezes é o começo da linha seguinte. Olhe o fim da linha anterior. Aula: Sintaxe.
‘x’ was not declared in this scope — nome que não existe
#include <iostream>
int main() {
int total = 10;
std::cout << totl << '\n';
}
$ g++ -std=c++23 -Wall -Wextra naodeclarada.cpp -o naodeclarada
naodeclarada.cpp: In function ‘int main()’:
naodeclarada.cpp:5:18: error: ‘totl’ was not declared in this scope; did you mean ‘total’?
5 | std::cout << totl << '\n';
| ^~~~
| total
naodeclarada.cpp:4:9: warning: unused variable ‘total’ [-Wunused-variable]
4 | int total = 10;
| ^~~~~
$ clang++ -std=c++23 -Wall -Wextra naodeclarada.cpp -o naodeclarada
naodeclarada.cpp:5:18: error: use of undeclared identifier 'totl'; did you mean 'total'?
5 | std::cout << totl << '\n';
| ^~~~
| total
naodeclarada.cpp:4:9: note: 'total' declared here
4 | int total = 10;
| ^
1 error generated.
O que significa: "totl não foi declarado neste escopo". As causas: nome digitado diferente (maiúsculas contam: Total ≠ total), variável criada depois da linha, ou criada dentro de outro bloco { } (veja Escopo). Sem nenhum tipo antes (idade = 30;), a mensagem é a mesma: em C++, toda variável precisa ser declarada com um tipo.
Como consertar: aceite a sugestão did you mean se ela fizer sentido, ou declare a variável antes de usar: int idade = 30;. Aula: Variáveis.
‘cout’ was not declared … did you mean ‘std::cout’? — faltou o std::
$ g++ -std=c++23 -Wall -Wextra semstd.cpp -o semstd
semstd.cpp: In function ‘int main()’:
semstd.cpp:4:5: error: ‘cout’ was not declared in this scope; did you mean ‘std::cout’?
4 | cout << "Olá\n";
| ^~~~
| std::cout
In file included from semstd.cpp:1:
/usr/include/c++/15/iostream:65:18: note: ‘std::cout’ declared here
65 | extern ostream cout; ///< Linked to standard output
| ^~~~
$ clang++ -std=c++23 -Wall -Wextra semstd.cpp -o semstd
semstd.cpp:4:5: error: use of undeclared identifier 'cout'; did you mean 'std::cout'?
4 | cout << "Olá\n";
| ^~~~
| std::cout
/usr/lib/gcc/x86_64-linux-gnu/15/../../../../include/c++/15/iostream:65:18: note: 'std::cout' declared here
65 | extern ostream cout; ///< Linked to standard output
| ^
1 error generated.
Com string nome = "Ana"; o g++ escreve error: ‘string’ was not declared in this scope e lista note: suggested alternatives: ‘std::string’; o clang++, error: unknown type name 'string'; did you mean 'std::string'?. Com endl: ‘endl’ was not declared in this scope; did you mean ‘std::endl’?.
O que significa: tudo da biblioteca padrão mora no "sobrenome" std (um namespace).
Como consertar: escreva std::cout, std::string, std::endl. Aula: Saída com cout.
‘setw’ is not a member of ‘std’ — faltou um #include
$ g++ -std=c++23 -Wall -Wextra semiomanip.cpp -o semiomanip
semiomanip.cpp: In function ‘int main()’:
semiomanip.cpp:4:23: error: ‘setw’ is not a member of ‘std’
4 | std::cout << std::setw(5) << 42 << '\n';
| ^~~~
semiomanip.cpp:2:1: note: ‘std::setw’ is defined in header ‘<iomanip>’; this is probably fixable by adding ‘#include <iomanip>’
1 | #include <iostream>
+++ |+#include <iomanip>
2 |
$ clang++ -std=c++23 -Wall -Wextra semiomanip.cpp -o semiomanip
semiomanip.cpp:4:18: error: no member named 'setw' in namespace 'std'; did you mean 'getw'?
4 | std::cout << std::setw(5) << 42 << '\n';
| ^~~~~~~~~
| getw
/usr/include/stdio.h:647:12: note: 'getw' declared here
647 | extern int getw (FILE *__stream) __nonnull ((1));
| ^
semiomanip.cpp:4:28: error: cannot initialize a parameter of type 'FILE *' (aka '_IO_FILE *') with an rvalue of type 'int'
4 | std::cout << std::setw(5) << 42 << '\n';
| ^
/usr/include/stdio.h:647:24: note: passing argument to parameter '__stream' here
647 | extern int getw (FILE *__stream) __nonnull ((1));
| ^
2 errors generated.
O que significa: "setw não é membro de std": o cabeçalho que o traz não foi incluído. O g++ ainda diz qual incluir (+++ |+#include <iomanip> mostra a linha a acrescentar). O clang++ tenta adivinhar um nome parecido (getw), que não tem nada a ver: ignore a sugestão.
Outras formas do mesmo problema: sem <map>, ‘map’ is not a member of ‘std’ (clang++: no template named 'map' in namespace 'std'; did you mean 'max'?); sem <cmath>, ‘sqrt’ was not declared in this scope; sem <vector>, uma mensagem estranha: error: wrong number of template arguments (1, should be 2) (clang++: too few template arguments for class template 'vector').
Como consertar: acrescente o #include certo no topo. Cuidado: às vezes um cabeçalho traz outro "de carona" e o programa compila sem o #include (no g++ 15, std::string funcionou só com <iostream>). Não conte com isso: inclua sempre o que usa. Aula: O Pré-processador.
fatal error: iostrem: Arquivo ou diretório inexistente
$ g++ -std=c++23 -Wall -Wextra arquivo.cpp -o arquivo
arquivo.cpp:1:10: fatal error: iostrem: Arquivo ou diretório inexistente
1 | #include <iostrem>
| ^~~~~~~~~
compilation terminated.
$ clang++ -std=c++23 -Wall -Wextra arquivo.cpp -o arquivo
arquivo.cpp:1:10: fatal error: 'iostrem' file not found
1 | #include <iostrem>
| ^~~~~~~~~
1 error generated.
O que significa: o arquivo pedido no #include não existe. fatal error para a compilação na hora (compilation terminated). O pedaço "Arquivo ou diretório inexistente" vem do sistema, por isso está em português; em inglês: No such file or directory.
Como consertar: confira a grafia (iostream). Para um arquivo seu, use aspas e confira a pasta: #include "soma.h". Aula: Arquivos .h e .cpp.
invalid conversion from ‘const char*’ to ‘int’ — tipo errado
$ cat tipo.cpp
int main() {
int idade = "30";
return idade;
}
$ g++ -std=c++23 -Wall -Wextra tipo.cpp -o tipo
tipo.cpp: In function ‘int main()’:
tipo.cpp:2:17: error: invalid conversion from ‘const char*’ to ‘int’ [-fpermissive]
2 | int idade = "30";
| ^~~~
| |
| const char*
$ clang++ -std=c++23 -Wall -Wextra tipo.cpp -o tipo
tipo.cpp:2:9: error: cannot initialize a variable of type 'int' with an lvalue of type 'const char[3]'
2 | int idade = "30";
| ^ ~~~~
1 error generated.
O que significa: "30", entre aspas, é texto (para o compilador, const char* ou const char[3]: dois caracteres mais o final invisível), e a variável é int. O C++ não converte texto em número sozinho.
Parentes: char letra = "A"; dá invalid conversion from ‘const char*’ to ‘char’ (use aspas simples: 'A'); std::string s = 5; dá conversion from ‘int’ to non-scalar type ‘std::string’ … requested (clang++: no viable conversion from 'int' to 'std::string').
Como consertar: tire as aspas (int idade = 30;) ou, se o texto vem de fora, converta com std::stoi. Aulas: Tipos de Dados, Texto ↔ Número, char.
no match for ‘operator<<’ — o cout não sabe mostrar isso
#include <iostream>
#include <vector>
int main() {
std::vector<int> v{1, 2, 3};
std::cout << v << '\n';
}
$ g++ -std=c++23 -Wall -Wextra coutvector.cpp -o coutvector
coutvector.cpp: In function ‘int main()’:
coutvector.cpp:6:15: error: no match for ‘operator<<’ (operand types are ‘std::ostream’ {aka ‘std::basic_ostream<char>’} and ‘std::vector<int>’)
6 | std::cout << v << '\n';
| ~~~~~~~~~ ^~ ~
| | |
| | std::vector<int>
| std::ostream {aka std::basic_ostream<char>}
coutvector.cpp:6:15: note: there are 52 candidates
« … mais 360 linhas de "candidate N: …", uma para cada tipo que o cout sabe mostrar …
$ clang++ -std=c++23 -Wall -Wextra coutvector.cpp -o coutvector
coutvector.cpp:6:15: error: invalid operands to binary expression ('ostream' (aka 'basic_ostream<char>') and 'std::vector<int>')
6 | std::cout << v << '\n';
| ~~~~~~~~~ ^ ~
« … mais 145 linhas de "candidate … not viable" …
O que significa: "não existe << que receba um ostream e um std::vector<int>". O cout sabe mostrar números, texto e caracteres, mas não um vetor inteiro (nem uma struct sua). As 52 "candidatas" são as versões de << que existem; nenhuma serve.
Como consertar: mostre item por item com um for de intervalo, ou use std::println("{}", v); do C++23, que sabe mostrar vetores (std::format e std::print). Para uma classe sua, ensine o << a ela (Sobrecarga de Operadores).
too few arguments to function / no matching function for call to
$ g++ -std=c++23 -Wall -Wextra argumentos.cpp -o argumentos
argumentos.cpp: In function ‘int main()’:
argumentos.cpp:6:16: error: too few arguments to function ‘int soma(int, int)’
6 | return soma(2);
| ~~~~^~~
argumentos.cpp:1:5: note: declared here
1 | int soma(int a, int b) {
| ^~~~
$ clang++ -std=c++23 -Wall -Wextra argumentos.cpp -o argumentos
argumentos.cpp:6:12: error: no matching function for call to 'soma'
6 | return soma(2);
| ^~~~
argumentos.cpp:1:5: note: candidate function not viable: requires 2 arguments, but 1 was provided
1 | int soma(int a, int b) {
| ^ ~~~~~~~~~~~~
1 error generated.
O que significa: "argumentos de menos para a função soma(int, int)": ela pede dois, você deu um. Com argumentos demais, too many arguments. Quando há várias versões da função (sobrecarga) e nenhuma serve, o g++ também diz no matching function for call to ‘…’ e lista as candidatas.
Como consertar: confira a assinatura que a nota declared here mostra e passe os argumentos na quantidade e nos tipos certos. Aulas: Parâmetros e Argumentos, Valores Padrão.
assignment of read-only variable — mudar uma constante
$ g++ -std=c++23 -Wall -Wextra const.cpp -o const
const.cpp: In function ‘int main()’:
const.cpp:3:12: error: assignment of read-only variable ‘maximo’
3 | maximo = 20;
| ~~~~~~~^~~~
$ clang++ -std=c++23 -Wall -Wextra const.cpp -o const
const.cpp:3:12: error: cannot assign to variable 'maximo' with const-qualified type 'const int'
3 | maximo = 20;
| ~~~~~~ ^
const.cpp:2:15: note: variable 'maximo' declared const here
2 | const int maximo = 10;
| ~~~~~~~~~~^~~~~~~~~~~
1 error generated.
O que significa: "atribuição a variável somente leitura": maximo foi declarada const. O compilador está fazendo o trabalho dele: proteger um valor que você mesmo disse que não muda.
Como consertar: se o valor precisa mudar, tire o const; se não, não mude. Aula: Constantes.
expected ‘}’ at end of input — faltou fechar uma chave
$ cat chave.cpp
#include <iostream>
int main() {
if (true) {
std::cout << "oi\n";
}
$ g++ -std=c++23 -Wall -Wextra chave.cpp -o chave
chave.cpp: In function ‘int main()’:
chave.cpp:6:2: error: expected ‘}’ at end of input
6 | }
| ^
chave.cpp:3:12: note: to match this ‘{’
3 | int main() {
| ^
$ clang++ -std=c++23 -Wall -Wextra chave.cpp -o chave
chave.cpp:6:2: error: expected '}'
6 | }
| ^
chave.cpp:3:12: note: to match this '{'
3 | int main() {
| ^
1 error generated.
O que significa: o arquivo acabou ("end of input") com uma { ainda aberta. A nota aponta a chave que ficou sem par, mas atenção: o compilador casa cada } com a { aberta mais recente, então a chave que de fato ficou sem fechar (aqui, a do if) pode ser outra.
O contrário, uma } sobrando, dá expected declaration before ‘}’ token (clang++: extraneous closing brace ('}')).
Como consertar: mantenha a indentação certinha (o editor ajuda) e confira bloco por bloco. Aula: Sintaxe.
Outros erros de compilação
A primeira linha da mensagem do g++ 15 (e, quando muda muito, a do clang++), a causa e a correção. Os nomes (x, Aluno…) são dos exemplos; no seu código, serão outros.
Sintaxe e texto
| Mensagem | Causa típica | Correção | Aula |
|---|---|---|---|
expected primary-expression before ‘;’ tokenclang++: expected expression | Faltou um pedaço da conta: int x = 5 * ;. Também aparece em cascata depois de outro erro. | Complete a expressão. | Aritméticos |
‘x’ does not name a typeclang++: a type specifier is required for all declarations | Uma instrução (x = 5;) fora de qualquer função. Fora de funções só cabem declarações. | Mova a instrução para dentro do main ou de outra função. | Funções |
‘::main’ must return ‘int’ | void main(), comum em livros antigos. | Use int main(). | Olá, Mundo |
redeclaration of ‘int x’clang++: redefinition of 'x' | Duas variáveis com o mesmo nome no mesmo bloco. | Para mudar o valor, tire o tipo: x = 2;. | Variáveis |
‘else’ without a previous ‘if’clang++: expected expression | Um ; logo depois do if (…), ou um else sobrando. | Tire o ;: if (x > 0) {. | if e else |
extended character “ is not valid in an identifierclang++: unexpected character <U+201C> | Aspas "curvas" (“Olá”), coladas de um site, do Word ou de um PDF. | Troque pelas aspas retas do teclado: "Olá". | Strings |
missing terminating " character | Abriu aspas e não fechou: "Olá << '\n';. Vem junto com outros erros em cascata. | Feche as aspas na mesma linha. | Strings |
invalid operands of types ‘const char [7]’ and ‘const char [4]’ to binary ‘operator+’ | Somar dois textos entre aspas: "Olá, " + "Ana". | Faça um deles virar std::string: std::string("Olá, ") + "Ana", ou junte numa só: "Olá, Ana". | Juntar Strings |
no match for ‘operator==’ (operand types are ‘std::string’ … and ‘char’) | Comparar texto com um caractere: nome == 'A'. | Use aspas duplas (nome == "A") ou compare um caractere (nome[0] == 'A'). | Acessar Caracteres |
narrowing conversion of ‘3.7000000000000002e+0’ from ‘double’ to ‘int’ [-Wnarrowing] | int x{3.7};: as chaves não deixam perder informação. | Use o tipo certo (double x{3.7};) ou converta de propósito: static_cast<int>(3.7). | Conversão de Tipos |
Funções, tipos e referências
| Mensagem | Causa típica | Correção | Aula |
|---|---|---|---|
void value not ignored as it ought to beclang++: cannot initialize a variable of type 'int' with an rvalue of type 'void' | Guardar o resultado de uma função void: int x = ola();. | Faça a função devolver um valor, ou só chame: ola();. | Retorno |
return-statement with no value, in function returning ‘int’ [-fpermissive]clang++: non-void function 'pega' should return a value | return; sozinho numa função que promete um int. | return 0; (ou o valor certo). | Retorno |
lvalue required as left operand of assignmentclang++: expression is not assignable | Do lado esquerdo do = há uma conta, não uma variável: if (x + 1 = 2). Quase sempre era ==. | Para comparar, use ==. | Comparação |
cannot bind non-const lvalue reference of type ‘int&’ to an rvalue of type ‘int’clang++: no matching function for call to 'dobra' | Passar um valor solto (dobra(5)) para um parâmetro int&, que precisa de uma variável para mudar. | Passe uma variável, ou use const int& se a função não muda o valor. | Por Referência |
call of overloaded ‘f(long int)’ is ambiguousclang++: call to 'f' is ambiguous | Duas versões da função servem igualmente bem. | Passe o tipo exato (f(5), f(5.0)) ou converta. | Sobrecarga |
switch quantity not an integer | switch com std::string. | Use if/else if, ou um enum. | switch |
jump to case label + note: crosses initialization of ‘int x’ | Uma variável criada dentro de um case sem chaves. | Ponha o case entre chaves: case 1: { int x = 5; … }. | switch |
‘println’ is not a member of ‘std’ + note: ‘std::println’ is only available from C++23 onwards | Compilou sem -std=c++23: o g++ 15 usa C++17 se você não pedir outro. | Use o comando padrão: g++ -std=c++23 …. | Compilar |
call to consteval function ‘std::basic_format_string<…>("{} tem {} anos")’ is not a constant expression | std::format/std::println com mais {} do que valores. O erro é pego na compilação. | Um valor para cada {}. | std::format |
Classes, ponteiros e containers
| Mensagem | Causa típica | Correção | Aula |
|---|---|---|---|
‘class std::vector<int>’ has no member named ‘length’clang++: no member named 'length' in 'std::vector<int>' | Método que não existe nesse tipo (no vetor, o tamanho é size()). | Confira o nome do método na referência. | Containers |
request for member ‘size’ in ‘p’, which is of pointer type … (maybe you meant to use ‘->’ ?) | Usar . num ponteiro. | p->size(). | Ponteiros |
‘double Conta::saldo’ is private within this contextclang++: 'saldo' is a private member of 'Conta' | Mexer num membro private de fora da classe (numa class, tudo é privado até um public:). | Use um método público, ou reveja o public:. | public e private |
no matching function for call to ‘Aluno::Aluno()’clang++: no matching constructor for initialization of 'Aluno' | Aluno a; sem argumentos, mas a classe só tem construtor que pede um nome. | Passe os argumentos (Aluno a{"Ana"};) ou crie um construtor padrão. | Construtores |
passing ‘const Aluno’ as ‘this’ argument discards qualifiers [-fpermissive]clang++: 'this' argument to member function 'nome' has type 'const Aluno', but function is not marked const | Chamar um método não-const num objeto const (por exemplo, recebido por const Aluno&). | Marque o método como const: std::string nome() const. | Métodos const |
cannot declare variable ‘f’ to be of abstract type ‘Forma’clang++: variable type 'Forma' is an abstract class | Criar um objeto de uma classe com método virtual puro (= 0). | Crie um objeto de uma classe filha que implemente o método. | Classes Abstratas |
‘void Gato::som()’ marked ‘override’, but does not override | A assinatura não bate com a da classe mãe (aqui faltou o const). | Copie a assinatura exata: void som() const override. | Polimorfismo |
use of deleted function ‘std::unique_ptr<…>::unique_ptr(const std::unique_ptr<…>&)’clang++: call to deleted constructor of … | Copiar um std::unique_ptr (auto b = a;): ele tem um dono só. | Transfira com auto b = std::move(a);, ou use std::shared_ptr. | Ponteiros Inteligentes |
wrong number of template arguments (1, should be 2) | Usou std::vector<int> sem #include <vector>. | Inclua <vector>. | std::vector |
Mensagens gigantes (templates e concepts)
Quando o erro acontece dentro de um template da biblioteca (std::sort, std::vector, cout <<…), o compilador mostra o caminho inteiro por dentro dela. O cout << v do erro 7 rende 378 linhas no g++. Não se assuste; procure três coisas:
- a primeira linha com
error:; - a linha
required from hereque aponta um arquivo seu (é a sua linha que causou tudo); - com concepts, a linha
the expression ‘…’ evaluated to ‘false’ourequired for the satisfaction of ‘…’, que diz qual exigência não foi cumprida.
Um filtro ajuda. Aqui, o std::sort numa std::list (veja a armadilha em Algoritmos), de 29 linhas reduzidas a 2:
$ g++ -std=c++23 -Wall -Wextra lista.cpp -o lista 2>&1 | grep -E "error|required from here" lista.cpp:6:14: required from here /usr/include/c++/15/bits/stl_algo.h:1907:50: error: no match for ‘operator-’ (operand types are ‘std::_List_iterator<int>’ and ‘std::_List_iterator<int>’)
(O 2>&1 manda as mensagens, que saem na saída de erro, para o grep.)
Com concepts C++20, a mensagem fica mais legível. Uma função que só aceita inteiros, chamada com 2.5:
#include <concepts>
template <std::integral T>
T dobro(T x) { return 2 * x; }
int main() {
dobro(2.5);
}
$ g++ -std=c++23 -Wall -Wextra concept.cpp -o concept
concept.cpp: In function ‘int main()’:
concept.cpp:7:10: error: no matching function for call to ‘dobro(double)’
7 | dobro(2.5);
| ~~~~~^~~~~
concept.cpp:7:10: note: there is 1 candidate
concept.cpp:4:3: note: candidate 1: ‘template<class T> requires integral<T> T dobro(T)’
4 | T dobro(T x) { return 2 * x; }
| ^~~~~
concept.cpp:4:3: note: template argument deduction/substitution failed:
concept.cpp:4:3: note: constraints not satisfied
In file included from concept.cpp:1:
/usr/include/c++/15/concepts: In substitution of ‘template<class T> requires integral<T> T dobro(T) [with T = double]’:
concept.cpp:7:10: required from here
7 | dobro(2.5);
| ~~~~~^~~~~
/usr/include/c++/15/concepts:109:13: required for the satisfaction of ‘integral<T>’ [with T = double]
/usr/include/c++/15/concepts:109:24: note: the expression ‘is_integral_v<_Tp> [with _Tp = double]’ evaluated to ‘false’
109 | concept integral = is_integral_v<_Tp>;
| ^~~~~~~~~~~~~~~~~~
$ clang++ -std=c++23 -Wall -Wextra concept.cpp -o concept
concept.cpp:7:5: error: no matching function for call to 'dobro'
7 | dobro(2.5);
| ^~~~~
concept.cpp:4:3: note: candidate template ignored: constraints not satisfied [with T = double]
4 | T dobro(T x) { return 2 * x; }
| ^
concept.cpp:3:11: note: because 'double' does not satisfy 'integral'
3 | template <std::integral T>
| ^
/usr/lib/gcc/x86_64-linux-gnu/15/../../../../include/c++/15/concepts:109:24: note: because 'is_integral_v<double>' evaluated to false
109 | concept integral = is_integral_v<_Tp>;
| ^
1 error generated.
Leitura: "não há dobro(double); a única candidata exige integral<T>, e com T = double isso deu false". O clang++ diz direto: 'double' does not satisfy 'integral'. Aulas: Templates de Função, Concepts.
Avisos (-Wall -Wextra)
Um aviso (warning) não impede o programa de ser criado, mas quase sempre aponta um defeito. Compile sempre com -Wall -Wextra e deixe a saída limpa. O nome entre colchetes é a opção que liga o aviso. Veja a aula Avisos.
| Aviso do g++ 15 | clang++ 21 | Causa e correção |
|---|---|---|
unused variable ‘x’ [-Wunused-variable] | unused variable 'x' | Criou e nunca usou. Apague, ou use. Aula: Variáveis. |
unused parameter ‘b’ [-Wunused-parameter] | unused parameter 'b' | Parâmetro que a função ignora. Se for de propósito, tire o nome: int f(int a, int). Aula: Parâmetros. |
variable ‘x’ set but not used [-Wunused-but-set-variable] | igual | Recebe valores, mas ninguém lê. Sobra de código antigo. |
comparison of integer expressions of different signedness: ‘int’ and ‘std::vector<int>::size_type’ {aka ‘long unsigned int’} [-Wsign-compare] | comparison of integers of different signs: 'int' and 'size_type' (aka 'unsigned long') | for (int i = 0; i < v.size(); i++): size() é sem sinal. Use std::size_t i ou, melhor, um for de intervalo. Aula: Inteiros. |
suggest parentheses around assignment used as truth value [-Wparentheses] | using the result of an assignment as a condition without parentheses | if (x = 5) atribui 5 e é sempre verdadeiro. Quase sempre era ==. Aula: Comparação. |
‘soma’ is used uninitialized [-Wuninitialized] | variable 'soma' is uninitialized when used here + sugestão = 0 | int soma; soma += 10;: o valor inicial é lixo. Inicialize: int soma = 0;. Aula: Comportamento Indefinido. |
no return statement in function returning non-void [-Wreturn-type] | non-void function does not return a value | A função promete um valor e acaba sem return. Compila, mas o resultado é indefinido. Aula: Retorno. |
address of local variable ‘x’ returned [-Wreturn-local-addr] | address of stack memory associated with local variable 'x' returned | Devolver &x de uma variável que morre no fim da função. Devolva o valor. Aula: Como a Memória Funciona. |
this statement may fall through [-Wimplicit-fallthrough=] | (o clang++ não avisa com -Wall -Wextra) | Um case sem break "cai" no próximo. Ponha o break; (ou [[fallthrough]]; se for de propósito). Aula: switch. |
suggest braces around empty body in an ‘if’ statement [-Wempty-body] | if statement has empty body | if (x > 0);: o ; é o corpo inteiro do if. Tire o ;. Aula: if e else. |
this ‘if’ clause does not guard... [-Wmisleading-indentation] | misleading indentation; statement is not part of the previous 'if' | Duas linhas recuadas debaixo de um if sem chaves: só a primeira é dele. Use sempre { }. |
division by zero [-Wdiv-by-zero] | division by zero is undefined | x / 0 escrito no código. Ao rodar, o programa morre (veja abaixo). |
integer overflow in expression of type ‘int’ results in ‘-2147483648’ [-Woverflow] | overflow in expression; result is -2'147'483'648 with type 'int' | A conta passa do maior int. Use long long. Aula: Inteiros. |
comparison of unsigned expression in ‘>= 0’ is always true [-Wtype-limits] | (não avisa) | for (unsigned i = 10; i >= 0; i--) nunca termina: um unsigned nunca é negativo. Use int. |
narrowing conversion of ‘preco’ from ‘double’ to ‘int’ [-Wnarrowing] | erro: type 'double' cannot be narrowed to 'int' in initializer list | int x{preco}; com uma variável double: o g++ só avisa, o clang++ recusa. Use static_cast<int>(preco). Aula: Conversão. |
infinite recursion detected [-Winfinite-recursion] | — | Função que chama a si mesma sem caso de parada. Aula: Recursão. |
ignoring return value of ‘…std::remove…’, declared with attribute ‘nodiscard’ [-Wunused-result] | ignoring return value of function declared with 'nodiscard' attribute | Jogou fora um resultado importante. Veja Algoritmos. |
deleting object of polymorphic class type ‘Base’ which has non-virtual destructor might cause undefined behavior [-Wdelete-non-virtual-dtor] | delete called on non-final 'Base' that has virtual functions but non-virtual destructor | Classe base com métodos virtual precisa de virtual ~Base() = default;. Aula: Polimorfismo. |
‘virtual void Animal::som() const’ was hidden [-Woverloaded-virtual=] | — | A classe filha criou um método com o mesmo nome e outra assinatura, escondendo o da mãe. |
Missão: o programa funciona, mas o compilador dá três avisos. Elimine todos (sem apagar a mensagem de saída) até a caixa compilar sem nenhum aviso e mostrar soma: 24.
#include <iostream>
#include <vector>
int main() {
std::vector<int> notas{7, 9, 8};
int soma = 0;
int maior = 0;
for (int i = 0; i < notas.size(); i++) {
soma += notas[i];
}
if (soma = 24) {
std::cout << "soma: " << soma << '\n';
}
}
#include <iostream>
#include <vector>
int main() {
std::vector<int> notas{7, 9, 8};
int soma = 0;
for (std::size_t i = 0; i < notas.size(); i++) {
soma += notas[i];
}
if (soma == 24) {
std::cout << "soma: " << soma << '\n';
}
}
Erros de ligação (ld)
Depois de compilar cada .cpp, o g++ chama o ligador (ld, de linker), que junta as peças num programa só. Os erros dele não têm número de linha: em vez de arquivo.cpp:5:5:, aparecem nomes de arquivos temporários (/tmp/ccsEstGP.o) e a frase collect2: error: ld returned 1 exit status ("o ld terminou com erro"). Na máquina da Ana, o ld fala português; com o sistema em inglês (LANG=C), a mesma mensagem fica como na segunda parte de cada exemplo. Aulas: Compilar Vários Arquivos e Arquivos .h e .cpp.
referência não definida para / undefined reference to
O main.cpp inclui soma.h (que só declara int soma(int a, int b);), mas a Ana compilou só o main.cpp, esquecendo o soma.cpp, onde a função é definida:
$ g++ -std=c++23 -Wall -Wextra main.cpp -o main /usr/bin/x86_64-linux-gnu-ld.bfd: /tmp/ccsEstGP.o: na função "main": main.cpp:(.text+0x13): referência não definida para "soma(int, int)" collect2: error: ld returned 1 exit status $ LANG=C g++ -std=c++23 -Wall -Wextra main.cpp -o main /usr/bin/x86_64-linux-gnu-ld.bfd: /tmp/ccTr6gcB.o: in function `main': main.cpp:(.text+0x13): undefined reference to `soma(int, int)' collect2: error: ld returned 1 exit status $ clang++ -std=c++23 -Wall -Wextra main.cpp -o main /usr/bin/x86_64-linux-gnu-ld.bfd: /tmp/main-e08580.o: na função "main": main.cpp:(.text+0xf): referência não definida para "soma(int, int)" clang++: error: linker command failed with exit code 1 (use -v to see invocation) $ g++ -std=c++23 -Wall -Wextra main.cpp soma.cpp -o main $ ./main 5
No editor do guia, o ligador é outro (wasm-ld) e a mesma falha aparece como wasm-ld: error: /tmp/main-62bf3f.o: undefined symbol: soma(int, int) ("símbolo não definido").
O que significa: "dentro da função main, há uma chamada a soma(int, int), mas ninguém a definiu". O compilador aceitou a chamada porque viu a declaração no .h; o ligador não achou o corpo da função.
Causas e consertos:
- esqueceu um
.cppno comando:g++ … main.cpp soma.cpp -o main; - o nome ou os parâmetros da definição não batem com a declaração (
int Soma(int a, int b)no.cpp,int soma(int, int)no.h: maiúscula conta); - a função foi declarada e nunca escrita;
- uma biblioteca externa não foi ligada (falta um
-lnome; veja Usar Bibliotecas Externas).
Um arquivo sem main dá a mesma família de erro: (.text+0x1b): referência não definida para "main" (em inglês, undefined reference to `main'), vinda de Scrt1.o: na função "_start", o código que o sistema roda antes do seu main.
múltiplas definições de / multiple definition of
O cabeçalho config.h define uma variável (int total = 0;) e é incluído em a.cpp e em b.cpp. Cada arquivo ganha a sua cópia, e o ligador não sabe com qual ficar:
$ g++ -std=c++23 -Wall -Wextra a.cpp b.cpp -o prog /usr/bin/x86_64-linux-gnu-ld.bfd: /tmp/ccfu3U3T.o:(.bss+0x0): múltiplas definições de "total"; /tmp/cciF57P8.o:(.bss+0x0): definido primeiro aqui collect2: error: ld returned 1 exit status $ LANG=C g++ -std=c++23 -Wall -Wextra a.cpp b.cpp -o prog /usr/bin/x86_64-linux-gnu-ld.bfd: /tmp/ccV3ztVv.o:(.bss+0x0): multiple definition of `total'; /tmp/ccw6qlvg.o:(.bss+0x0): first defined here collect2: error: ld returned 1 exit status
O #pragma once não resolve: ele evita incluir o mesmo .h duas vezes no mesmo .cpp, não em dois .cpp diferentes.
Como consertar: no .h, use inline int total = 0; C++17 (uma variável compartilhada, permitida em vários arquivos), ou declare com extern int total; no .h e defina int total = 0; num .cpp só. Para funções escritas no .h, a mesma regra: marque-as inline.
Missão: o programa tem três arquivos (abas). Clique em Rodar: a compilação passa, mas a ligação falha, porque a função chamada no main.cpp não foi definida com o mesmo nome. Conserte o soma.cpp até o programa mostrar 5.
#include <iostream>
#include "soma.h"
int main() {
std::cout << soma(2, 3) << '\n';
}
#pragma once int soma(int a, int b);
#include "soma.h"
int Soma(int a, int b) {
return a + b;
}
#include "soma.h"
int soma(int a, int b) {
return a + b;
}
Erros de execução
O programa compilou, ligou, começou a rodar… e morreu. Quem escreve a mensagem final é o terminal (o bash), que na máquina da Ana fala português; a versão em inglês está ao lado. "Imagem do núcleo gravada" (core dumped) quer dizer que o sistema pode ter salvado uma "foto" da memória do programa para análise (veja Depurar com o GDB). As saídas abaixo foram feitas num terminal de verdade.
Falha de segmentação / Segmentation fault — código 139
#include <iostream>
int main() {
int* p = nullptr;
std::cout << "antes\n";
std::cout << *p << '\n';
}
$ g++ -std=c++23 -Wall -Wextra nulo.cpp -o nulo $ ./nulo antes Falha de segmentação (imagem do núcleo gravada) ./nulo $ echo $? 139
Em inglês: Segmentation fault (core dumped) ./nulo.
O que significa: o programa tentou ler ou escrever numa parte da memória que não é dele, e o sistema o matou com o sinal SIGSEGV. Causas típicas: usar um ponteiro nulo (*p com p = nullptr), um ponteiro para algo que já foi apagado, um índice muito fora do array, ou uma recursão sem fim, que estoura a pilha (a conta(n + 1) sem caso de parada deu a mesma mensagem e o mesmo 139).
Como consertar: confira ponteiros antes de usar (if (p != nullptr)), prefira std::vector e ponteiros inteligentes, e use o gdb ou os sanitizers para achar a linha. Aulas: Ponteiros, nullptr.
Exceção de ponto flutuante / Floating point exception — código 136
#include <iostream>
int main() {
int total = 10, pessoas = 0;
std::cin >> pessoas;
std::cout << total / pessoas << '\n';
}
$ echo 0 | ./divisao Exceção de ponto flutuante (imagem do núcleo gravada) echo 0 | ./divisao $ echo $? 136
Em inglês: Floating point exception (core dumped) echo 0 | ./divisao.
O que significa: apesar do nome, é uma divisão inteira por zero (ou o resto % por zero). O processador recusa a conta e o sistema mata o programa com o sinal SIGFPE. Com double, dividir por zero não mata o programa: dá inf ou nan.
Como consertar: confira o divisor antes: if (pessoas == 0) { … }. Aulas: Aritméticos, Validar a Entrada.
terminate called after throwing an instance of … + Abortado — código 134
#include <iostream>
#include <vector>
int main() {
std::vector<int> notas{7, 9, 8};
std::cout << notas.at(10) << '\n';
}
$ ./at terminate called after throwing an instance of 'std::out_of_range' what(): vector::_M_range_check: __n (which is 10) >= this->size() (which is 3) Abortado (imagem do núcleo gravada) ./at $ echo $? 134
Em inglês, a última linha fica Aborted (core dumped) ./at.
O que significa: uma exceção foi lançada e ninguém a capturou com try/catch. O C++ então chama std::terminate, que mostra o tipo da exceção (std::out_of_range) e a mensagem dela (what():), e aborta o programa com o sinal SIGABRT. Aqui: "índice 10 ≥ tamanho 3".
As que mais aparecem (todas reais, todas com código 134):
Tipo e what() | Quem lança | Aula |
|---|---|---|
'std::out_of_range'what(): vector::_M_range_check: __n (which is 10) >= this->size() (which is 3) | v.at(i) ou s.at(i) com índice fora do tamanho. | std::vector |
'std::invalid_argument'what(): stoi | std::stoi("trinta"): o texto não começa com um número. | Texto ↔ Número |
'std::runtime_error'what(): saldo insuficiente | O seu próprio throw std::runtime_error("saldo insuficiente");. | Exceções |
'int' (sem what()) | throw 42;: dá para lançar qualquer coisa, mas prefira as classes de <stdexcept>. | Exceções |
'std::bad_alloc'what(): std::bad_alloc | Faltou memória (aqui, um std::vector<int> de 5 bilhões de itens com a memória limitada por ulimit -v). | new e delete |
'std::bad_optional_access'what(): bad optional access | x.value() num std::optional vazio. | optional e variant |
Como consertar: evite a causa (confira o índice, valide o texto) ou capture a exceção onde você sabe o que fazer: try { … } catch (const std::exception& e) { std::cout << e.what(); }.
Assertion '__n < this->size()' failed. — índice fora com [ ]
$ cat colchete.cpp
#include <iostream>
#include <vector>
int main() {
std::vector<int> notas{7, 9, 8};
std::cout << notas[10] << '\n';
}
$ g++ -std=c++23 -Wall -Wextra colchete.cpp -o colchete
$ ./colchete
/usr/include/c++/15/bits/stl_vector.h:1263: constexpr std::vector< <template-parameter-1-1>, <template-parameter-1-2> >::reference std::vector< <template-parameter-1-1>, <template-parameter-1-2> >::operator[](size_type) [with _Tp = int; _Alloc = std::allocator<int>; reference = int&; size_type = long unsigned int]: Assertion '__n < this->size()' failed.
Abortado (imagem do núcleo gravada) ./colchete
$ g++ -std=c++23 -Wall -Wextra -O2 colchete.cpp -o colchete 2>/dev/null
$ ./colchete
0
O que significa: o [ ] do vetor não confere o índice, ao contrário do .at(). Mas a biblioteca do g++ 15, quando você compila sem otimização (sem -O2), liga umas conferências extras ("asserções") que pegam o erro e abortam (código 134). Com -O2, as conferências somem e o programa simplesmente lê lixo da memória e mostra 0 (ou qualquer outra coisa): é comportamento indefinido.
Como consertar: confira o índice (i < notas.size()), use for de intervalo, ou .at() quando o índice vem de fora.
free(): double free detected in tcache 2 — apagou duas vezes
$ cat doublefree.cpp
int main() {
int* p = new int(5);
delete p;
delete p;
}
$ ./doublefree
free(): double free detected in tcache 2
Abortado (imagem do núcleo gravada) ./doublefree
$ echo $?
134
O que significa: o mesmo bloco de memória foi devolvido duas vezes. A biblioteca C percebeu e abortou. (tcache é o nome de uma "gaveta" interna do gerenciador de memória.) Nem sempre o erro é pego: às vezes o programa continua e falha bem depois, num lugar sem relação.
Como consertar: não use new/delete à mão: std::unique_ptr, std::vector e std::string liberam a memória sozinhos, uma vez só. Aulas: new e delete, Ponteiros Inteligentes, RAII.
Códigos de saída e sinais
Depois que o programa termina, echo $? mostra o código de saída. Quando o sistema mata o programa com um sinal, o código é 128 + o número do sinal. Os nomes dos sinais vêm do comando kill -l:
$ kill -l 6 8 9 11 ABRT FPE KILL SEGV
| Código | Sinal | Mensagem do terminal (pt / en) | Causas típicas |
|---|---|---|---|
0 | — | nenhuma | Deu tudo certo (o main terminou ou fez return 0). |
1 (ou outro pequeno) | — | nenhuma | O próprio programa escolheu: return 1;. Também é o código de um relatório do AddressSanitizer e do g++ quando a compilação falha. |
124 | — | nenhuma | O comando timeout parou o programa porque o tempo acabou (um laço infinito, por exemplo). |
134 | 6, SIGABRT | Abortado / Aborted | Exceção não capturada (terminate called…), double free, asserção que falhou, std::abort(). |
136 | 8, SIGFPE | Exceção de ponto flutuante / Floating point exception | Divisão inteira (ou %) por zero. |
137 | 9, SIGKILL | Morto / Killed | Morto à força: kill -9, timeout -s KILL, ou o sistema sem memória. |
139 | 11, SIGSEGV | Falha de segmentação / Segmentation fault | Ponteiro nulo ou inválido, índice muito fora, recursão infinita. |
Relatórios dos sanitizers (resumidos)
Os sanitizers são "fiscais" que o compilador põe dentro do programa para pegar erros de memória e comportamento indefinido na linha exata, mesmo quando o programa parece funcionar. Compile com -g -fsanitize=address,undefined. Aula completa: Sanitizers.
Um exemplo inteiro: o laço vai até i <= 3 num array de 3 itens criado com new.
#include <iostream>
int main() {
int* notas = new int[3]{7, 9, 8};
int soma = 0;
for (int i = 0; i <= 3; i++) {
soma += notas[i];
}
std::cout << soma << '\n';
delete[] notas;
}
$ g++ -std=c++23 -Wall -Wextra -g -fsanitize=address,undefined heapnew.cpp -o heapnew && ./heapnew
=================================================================
==534580==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x73adb6be001c at pc 0x624669b21612 bp 0x7fff3740ad40 sp 0x7fff3740ad30
READ of size 4 at 0x73adb6be001c thread T0
#0 0x624669b21611 in main /home/ana/erros/run/heapnew.cpp:7
#1 0x778db782a600 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:59
#2 0x778db782a717 in __libc_start_main_impl ../csu/libc-start.c:360
#3 0x624669b21264 in _start (/home/ana/erros/run/heapnew+0x2264) (BuildId: 6e911907011ca067d2d483d8ef96462400e25fcf)
0x73adb6be001c is located 0 bytes after 12-byte region [0x73adb6be0010,0x73adb6be001c)
allocated by thread T0 here:
#0 0x778db892c8cf in operator new[](unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:111
#1 0x624669b21345 in main /home/ana/erros/run/heapnew.cpp:4
« … (#2 a #4: as mesmas linhas de inicialização de cima) …
SUMMARY: AddressSanitizer: heap-buffer-overflow /home/ana/erros/run/heapnew.cpp:7 in main
Shadow bytes around the buggy address:
« … 30 linhas de "bytes-sombra" (o mapa interno da memória): pode pular …
==534580==ABORTING
$ echo $?
1
Como ler: ERROR: AddressSanitizer: heap-buffer-overflow é o tipo do erro; READ of size 4, "leitura de 4 bytes" (um int); #0 … in main …/heapnew.cpp:7, a linha culpada; 0 bytes after 12-byte region, "logo depois de um bloco de 12 bytes" (3 ints); allocated by thread T0 here: … heapnew.cpp:4, onde o bloco foi criado. A linha SUMMARY resume tudo. O número ==534580== é o número do processo.
| Linha principal do relatório (real) | O que aconteceu |
|---|---|
ERROR: AddressSanitizer: heap-buffer-overflow on address … | Leu ou escreveu além do fim (ou antes do começo) de um bloco criado com new (ou dentro de um vector, string…). |
ERROR: AddressSanitizer: stack-buffer-overflow on address …[32, 44) 'a' (line 4) <== Memory access at offset 44 overflows this variable | O mesmo, num array local (int a[3] lido em a[3]). O relatório até diz qual variável. |
ERROR: AddressSanitizer: heap-use-after-free on address …com freed by thread T0 here: e previously allocated by thread T0 here: | Usou memória depois do delete. O relatório mostra três linhas: onde usou, onde apagou, onde criou. |
ERROR: LeakSanitizer: detected memory leaksDirect leak of 40 byte(s) in 1 object(s) allocated from:SUMMARY: AddressSanitizer: 40 byte(s) leaked in 1 allocation(s). | Vazamento: um new int[10] (40 bytes) nunca foi apagado. Aparece no fim do programa. |
overflow.cpp:6:7: runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int' | (UndefinedBehaviorSanitizer) A conta passou do maior int. O programa continua e mostra -2147483648. Aula: Inteiros. |
pilhaarray.cpp:6:21: runtime error: index 3 out of bounds for type 'int [3]' | (UBSan) Índice fora de um array comum, avisado antes mesmo do AddressSanitizer. |
O editor compila com o Clang e roda o programa como WebAssembly, dentro do navegador. Os erros de compilação são os da coluna do clang++. Os de ligação e de execução não vêm do ld nem do bash do Linux, e a memória do WebAssembly funciona de outro jeito, então o resultado muda. Os mesmos programas desta página, rodados no editor:
| Programa | No terminal (g++) | No editor do guia |
|---|---|---|
| função sem definição | undefined reference to `soma(int, int)' | wasm-ld: error: /tmp/main-62bf3f.o: undefined symbol: soma(int, int) |
at.cpp (exceção não capturada) | terminate called after throwing an instance of 'std::out_of_range', código 134 | libc++abi: terminating due to uncaught exception of type std::out_of_range: vector, código 134 |
divisao.cpp (divisão por zero) | Exceção de ponto flutuante, código 136 | sem mensagem, código 136 |
nulo.cpp (*p com p = nullptr) | Falha de segmentação, código 139 | não trava: mostra antes e 0, código 0 |
colchete.cpp, doublefree.cpp | abortam (código 134) | não acusam nada: mostram 0 ou nada, código 0 |
Repare nas duas últimas linhas: o comportamento indefinido pode parecer funcionar. Um programa que "deu certo" no editor ainda pode ter um erro de memória; para caçá-los, compile no seu terminal com os sanitizers (Instalar no Linux). Mais sobre o editor em O Editor do Guia.
Exercícios
1. A mensagem é main.cpp:(.text+0x13): undefined reference to `soma(int, int)' seguida de collect2: error: ld returned 1 exit status. Em que etapa está o problema?
2. Um programa morre e echo $? mostra 136. Qual é a causa mais provável?
3. O g++ mostrou quatro erros. O primeiro é expected ‘,’ or ‘;’ before ‘int’ na linha 5. Qual é a melhor atitude?
4. Qual cabeçalho?
O g++ disse ‘setw’ is not a member of ‘std’. Complete a linha que resolve:
5. 128 + sinal
O sinal SIGSEGV é o número 11. Que código de saída aparece em echo $? depois de uma "Falha de segmentação"?
Resumo
- Leia
arquivo:linha:coluna: error: texto, conserte o primeiro erro e compile de novo: os outros costumam ser cascata. errorimpede o programa;warningdeixa criar, mas aponta defeito;noteexplica a mensagem anterior. Compile com-Wall -Wextrae zere os avisos.- O editor do guia usa o Clang: as palavras mudam (
was not declared×use of undeclared identifier), o sentido é o mesmo. - Erro de ligação (
undefined reference,multiple definition,ld returned 1 exit status): falta ou sobra uma peça entre os arquivos. - Erros de execução: 139 =
Segmentation fault, 136 =Floating point exception, 134 =Aborted(exceção não capturada,double free, asserção). - Para achar a linha de um erro de memória, use
-g -fsanitize=address,undefinede leia oSUMMARY.