C Avisos (-Wall -Wextra)

Um erro impede o programa de existir. Um aviso (warning) deixa o programa ser criado, mas o compilador comenta: "isto aqui está com cara de engano". Muitos iniciantes ignoram os avisos, porque "o programa rodou". Nesta aula você vai ver, com resultados reais, programas que compilam, rodam e dão a resposta errada, e como o compilador avisou de cada um deles, para quem pediu.

Você vai aprender
  • A diferença entre aviso e erro, e como reconhecer um aviso na tela.
  • O que -Wall e -Wextra ligam, e por que não vêm ligados de fábrica.
  • Os avisos que salvam programas: formato errado no printf, = no lugar de ==, int comparado com unsigned, variável sem valor e outros.
  • Por que alguns avisos só aparecem com -O2.
  • Os avisos que o gcc 15 já trata como erro.
  • -Werror (avisos viram erros), -Wconversion (mais avisos) e -w (que você nunca deve usar).

Os programas foram compilados na máquina fictícia da Ana com o gcc 15.2, na pasta ~/c/avisos, e as mensagens do Clang são as do editor do guia. Alguns usam recursos das próximas aulas (variáveis, if); para esta aula, basta entender a ideia de cada um, que está explicada ao lado.


A ideia: a luz do painel do carro

Quando a luz do óleo acende no painel, o carro continua andando. Dá para ir trabalhar, voltar, passar a semana assim. Até o dia em que o motor funde. A luz não era o problema: era o aviso do problema.

Os avisos do compilador são essas luzes. E, por padrão, o gcc vem com quase todas elas desligadas, para não incomodar quem compila código antigo (há programas em C com 40 anos de idade, e eles teriam milhares de avisos). As opções -Wall e -Wextra, que você conheceu em Compilar com gcc, acendem o painel.


1. Aviso × erro

Erro (error:)Aviso (warning:)
O código segue as regras do C?NãoSim
O programa é criado?NãoSim
Quer dizer que…"Não entendi o que você escreveu.""Entendi, mas duvido que você quisesse isso."
No fim da mensagem(nada, ou o nome do aviso que virou erro)O nome do aviso entre colchetes, como [-Wunused-variable]

Um aviso tem o mesmo formato de um erro (aula Lendo Erros do Compilador), com warning: no lugar de error::

#include <stdio.h>

int main(void) {
    int itens = 3;
    printf("Lista de compras da Ana\n");
    return 0;
}
$ gcc -std=c23 compras.c -o compras
$                        « sem -Wall: silêncio
$ gcc -std=c23 -Wall -Wextra compras.c -o compras
compras.c: In function ‘main’:
compras.c:4:9: warning: unused variable ‘itens’ [-Wunused-variable]
    4 |     int itens = 3;
      |         ^~~~~
compras.c:4:9:
Arquivo, linha e coluna, como num erro.
warning:
"Aviso". O programa foi criado.
unused variable ‘itens’
"Variável não usada: itens". A Ana guardou o número 3 e nunca mais olhou para ele.
[-Wunused-variable]
O nome do aviso: é a opção que o liga (e o termo para pesquisar, se a mensagem não ficar clara). Ele faz parte do grupo -Wall.

Uma variável não usada não quebra nada. Mas é uma pista: ou sobrou de uma versão antiga do código (apague), ou você esqueceu de usá-la (a Ana queria mostrar "3 itens"). O aviso apontou o esquecimento.


2. O que -Wall e -Wextra ligam

  • -Wall (all, "todos"): liga os avisos que quase sempre indicam um problema real. Apesar do nome, não são todos.
  • -Wextra (extra): liga mais alguns, um pouco mais exigentes.

Um aviso do -Wextra: a main pode receber as palavras digitadas depois do nome do programa (argc e argv, aula Argumentos da Linha de Comando). Receber e não usar dá aviso, mas só com -Wextra:

$ gcc -std=c23 -Wall args.c -o args                      « int main(int argc, char *argv[]) {
$                        « só -Wall: nada
$ gcc -std=c23 -Wall -Wextra args.c -o args
args.c: In function ‘main’:
args.c:3:14: warning: unused parameter ‘argc’ [-Wunused-parameter]
    3 | int main(int argc, char *argv[]) {
      |          ~~~~^~~~
args.c:3:26: warning: unused parameter ‘argv’ [-Wunused-parameter]
    3 | int main(int argc, char *argv[]) {
      |                    ~~~~~~^~~~~~

"Parâmetro não usado". Conserto: se a main não usa os argumentos, escreva int main(void), como o guia faz.

E há avisos que o gcc dá mesmo sem -Wall, de tão graves: os de formato errado no printf (seção 3.1) aparecem nos dois casos. Mas não conte com isso: a maioria, como o de função que não devolve valor (seção 3.6), só vem com -Wall. O Clang, o compilador do editor do guia, reconhece as mesmas opções e dá os avisos com os mesmos nomes entre colchetes. O editor compila sempre com -Wall -Wextra e mostra os avisos antes da saída do programa.


3. Avisos que salvam programas

3.1. Formato errado no printf

Cada lacuna do printf espera um tipo de valor: %d um inteiro, %f um número com vírgula (aula Formatos do printf). Trocar um pelo outro não dá erro, mas o resultado é lixo:

#include <stdio.h>

int main(void) {
    int idade = 29;
    double altura = 1.65;
    printf("Idade: %f\n", idade);
    printf("Altura: %d\n", altura);
    return 0;
}
$ gcc -std=c23 -Wall -Wextra formato.c -o formato && ./formato
formato.c: In function ‘main’:
formato.c:6:21: warning: format ‘%f’ expects argument of type ‘double’, but argument 2 has type ‘int’ [-Wformat=]
    6 |     printf("Idade: %f\n", idade);
      |                    ~^     ~~~~~
      |                     |     |
      |                     |     int
      |                     double
      |                    %d
formato.c:7:22: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘double’ [-Wformat=]
    7 |     printf("Altura: %d\n", altura);
      |                     ~^     ~~~~~~
      |                      |     |
      |                      int   double
      |                     %f
Idade: 0.000000             « a idade era 29!
Altura: -48263632           « lixo, que muda de uma vez para outra

"O formato %f espera um argumento do tipo double, mas o argumento 2 é do tipo int". Repare no desenho: embaixo da lacuna, o tipo que ela espera (double); embaixo do valor, o tipo que ele tem (int); e na última linha, a lacuna certa sugerida (%d). No Clang: format specifies type 'double' but the argument has type 'int', também com a sugestão.

Conserto: a lacuna do tipo certo: %d para a idade, %f (ou %.2f) para a altura.

Missão: rode e veja o lixo e os avisos. Troque as lacunas para o programa mostrar Idade: 29 e a altura começando por Altura: 1.65, sem nenhum aviso.

#include <stdio.h>

int main(void) {
    int idade = 29;
    double altura = 1.65;
    printf("Idade: %f\n", idade);
    printf("Altura: %d\n", altura);
    return 0;
}
#include <stdio.h>

int main(void) {
    int idade = 29;
    double altura = 1.65;
    printf("Idade: %d\n", idade);
    printf("Altura: %.2f\n", altura);
    return 0;
}

3.2. = no lugar de ==

Em C, = guarda um valor (atribuição) e == compara dois valores (aulas Atribuição e Comparação). Trocar um pelo outro é um dos erros mais comuns da programação. A Ana tirou 4 e quer parabenizar só quem tirou 10:

#include <stdio.h>

int main(void) {
    int nota = 4;
    if (nota = 10) {
        printf("Nota máxima!\n");
    }
    printf("A nota é %d\n", nota);
    return 0;
}

O if ("se") executa o bloco só se a condição for verdadeira (aula if e else). Ela queria escrever "se a nota for igual a 10", mas escreveu "guarde 10 na nota":

$ gcc -std=c23 igual.c -o igual && ./igual
Nota máxima!             « errado: a nota era 4!
A nota é 10              « e pior: o 4 foi apagado e virou 10
$ gcc -std=c23 -Wall -Wextra igual.c -o igual && ./igual
igual.c: In function ‘main’:
igual.c:5:9: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
    5 |     if (nota = 10) {
      |         ^~~~
Nota máxima!
A nota é 10

Sem -Wall, compila em silêncio, roda, e as duas linhas estão erradas. Com -Wall: "sugiro parênteses em volta da atribuição usada como valor de verdade". Em outras palavras: "você usou uma atribuição (=) como condição; se era isso mesmo, ponha parênteses extras para eu saber". Quase nunca era. O Clang é ainda mais claro e oferece as duas saídas:

$ clang -std=c23 -Wall -Wextra igual.c -o igual
igual.c:5:14: warning: using the result of an assignment as a condition without parentheses [-Wparentheses]
    5 |     if (nota = 10) {
      |         ~~~~~^~~~
igual.c:5:14: note: place parentheses around the assignment to silence this warning
    5 |     if (nota = 10) {
      |              ^
      |         (        )
igual.c:5:14: note: use '==' to turn this assignment into an equality comparison
    5 |     if (nota = 10) {
      |              ^
      |              ==
1 warning generated.

A segunda nota: "use == para transformar esta atribuição numa comparação de igualdade". Conserto: if (nota == 10).

Missão: rode e veja o aviso. Corrija o programa para que ele não mostre "Nota máxima!" para uma nota 4, mostre A nota é 4 e compile sem nenhum aviso.

#include <stdio.h>

int main(void) {
    int nota = 4;
    if (nota = 10) {
        printf("Nota máxima!\n");
    }
    printf("A nota é %d\n", nota);
    return 0;
}
#include <stdio.h>

int main(void) {
    int nota = 4;
    if (nota == 10) {
        printf("Nota máxima!\n");
    }
    printf("A nota é %d\n", nota);
    return 0;
}

3.3. Comparar int com unsigned (só com -Wextra)

O C tem números inteiros com sinal (int, que aceita negativos) e sem sinal (unsigned int, só zero e positivos; aula Inteiros). Misturar os dois numa comparação dá um resultado surpreendente. A Ana está com o saldo negativo, −1, e o limite é 10:

#include <stdio.h>

int main(void) {
    int saldo = -1;
    unsigned int limite = 10;
    if (saldo < limite) {
        printf("Saldo abaixo do limite\n");
    } else {
        printf("Saldo OK\n");
    }
    return 0;
}
$ gcc -std=c23 -Wall sinal.c -o sinal && ./sinal
Saldo OK                 « −1 não é menor que 10?! E o -Wall não disse nada
$ gcc -std=c23 -Wall -Wextra sinal.c -o sinal && ./sinal
sinal.c: In function ‘main’:
sinal.c:6:15: warning: comparison of integer expressions of different signedness: ‘int’ and ‘unsigned int’ [-Wsign-compare]
    6 |     if (saldo < limite) {
      |               ^
Saldo OK

−1 é menor que 10, mas o programa disse que não. O que aconteceu: para comparar, o C converteu o -1 para unsigned, e −1 sem sinal vira um número enorme (4294967295), que não é menor que 10. O aviso "comparação de expressões inteiras com sinais diferentes" só veio com o -Wextra: em C, o -Wsign-compare não faz parte do -Wall. É um bom exemplo de por que o guia usa os dois. No Clang: comparison of integers of different signs: 'int' and 'unsigned int'.

Conserto: compare valores do mesmo tipo (aqui, int limite = 10;).

3.4. Variável sem valor

Em C, uma variável criada sem valor inicial (int pontos;) não vale zero: ela contém o que estiver naquele pedaço da memória, um valor "lixo". Usá-la antes de dar um valor é comportamento indefinido: o programa pode fazer qualquer coisa (aula Comportamento Indefinido).

$ cat semvalor.c
#include <stdio.h>

int main(void) {
    int pontos;
    printf("Pontos: %d\n", pontos);
    return 0;
}
$ gcc -std=c23 semvalor.c -o semvalor && ./semvalor
Pontos: 0                « deu 0 por sorte; não conte com isso
$ gcc -std=c23 -Wall -Wextra semvalor.c -o semvalor
semvalor.c: In function ‘main’:
semvalor.c:5:5: warning: ‘pontos’ is used uninitialized [-Wuninitialized]
    5 |     printf("Pontos: %d\n", pontos);
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
semvalor.c:4:9: note: ‘pontos’ was declared here
    4 |     int pontos;
      |         ^~~~~~

"pontos é usada sem ter sido inicializada" (sem valor inicial), e a note diz onde ela foi criada. O Clang ainda sugere o conserto:

$ clang -std=c23 -Wall -Wextra semvalor.c -o semvalor
semvalor.c:5:28: warning: variable 'pontos' is uninitialized when used here [-Wuninitialized]
    5 |     printf("Pontos: %d\n", pontos);
      |                            ^~~~~~
semvalor.c:4:15: note: initialize the variable 'pontos' to silence this warning
    4 |     int pontos;
      |               ^
      |                = 0
1 warning generated.

Conserto: dê sempre um valor ao criar a variável: int pontos = 0;. É uma regra do guia desde a aula Variáveis.

3.5. O aviso que só aparece com -O2

No caso acima, a variável nunca recebe valor, e o gcc percebe de cara. Mas quando ela recebe valor às vezes, perceber exige uma análise mais funda do programa, que o gcc só faz quando otimiza (-O2, aula Compilar com gcc). Neste programa (o scanf lê um número do teclado e o switch escolhe um caso; aulas Entrada com scanf e switch), o desconto só recebe valor para os tipos 1 e 2:

#include <stdio.h>

int main(void) {
    int tipo = 0;
    if (scanf("%d", &tipo) != 1) {
        return 1;
    }
    int desconto;
    switch (tipo) {
        case 1: desconto = 5; break;
        case 2: desconto = 10; break;
    }
    printf("Desconto: %d%%\n", desconto);
    return 0;
}
$ gcc -std=c23 -Wall -Wextra v1.c -o v1
$                        « sem -O2: nenhum aviso
$ gcc -std=c23 -Wall -Wextra -O2 v1.c -o v1
In file included from /usr/include/stdio.h:974,
                 from v1.c:1:
In function ‘printf’,
    inlined from ‘main’ at v1.c:13:5:
/usr/include/x86_64-linux-gnu/bits/stdio2.h:118:10: warning: ‘desconto’ may be used uninitialized [-Wmaybe-uninitialized]
  118 |   return __printf_chk (__USE_FORTIFY_LEVEL - 1, __fmt, __va_arg_pack ());
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
v1.c: In function ‘main’:
v1.c:8:9: note: ‘desconto’ was declared here
    8 |     int desconto;
      |         ^~~~~~~~
$ echo 1 | ./v1          « o echo … | digita o número para o programa
Desconto: 5%
$ echo 3 | ./v1
Desconto: 0%             « tipo 3: não tem desconto, e saiu 0 por sorte

"desconto pode ser usada sem valor" (may be: em algum caminho, sim; aqui, no tipo 3). A mensagem assusta, porque começa dentro da biblioteca: com -O2, o gcc "colou" o código do printf dentro da main (inlined from ‘main’ at v1.c:13:5, "copiado para dentro da main, na linha 13") e reclamou lá dentro. Leia as partes que falam do seu arquivo: a linha 13 (o printf) e a note da linha 8 (onde a variável foi criada). E o 0%? Saiu por sorte: é o mesmo lixo da seção 3.4, que pode mudar com outro compilador ou outra opção. Por isso, de vez em quando, compile também com -O2, só para ver se aparecem avisos novos.

Conserto: int desconto = 0;. Com um valor inicial, todos os caminhos ficam cobertos.

3.6. Outros avisos que você vai encontrar

$ gcc -std=c23 -Wall -Wextra efeito.c -o efeito          « total == 20;
efeito.c: In function ‘main’:
efeito.c:5:11: warning: statement with no effect [-Wunused-value]
    5 |     total == 20;
      |     ~~~~~~^~~~~
$ gcc -std=c23 -Wall -Wextra coment.c -o coment && ./coment       « // fotos em C:\fotos\
coment.c: In function ‘main’:
coment.c:4:5: warning: multi-line comment [-Wcomment]
    4 |     // fotos em C:\fotos\
      |     ^
$                        « o printf("Fotos salvas!\n") da linha 5 sumiu
$ gcc -std=c23 dobro.c -o dobro                            « sem -Wall: nada
$ gcc -std=c23 -Wall -Wextra dobro.c -o dobro
dobro.c: In function ‘dobro’:
dobro.c:7:1: warning: control reaches end of non-void function [-Wreturn-type]
    7 | }
      | ^
Aviso (gcc)ExemploO que quer dizer
statement with no effect [-Wunused-value]total == 20;Uma comparação solta, que não faz nada. Provavelmente era total = 20;. (Clang: equality comparison result unused, e sugere o =.)
multi-line comment [-Wcomment]// C:\fotos\A barra invertida no fim do comentário "cola" a linha seguinte nele: o printf virou comentário (aula Comentários).
control reaches end of non-void function [-Wreturn-type]Uma função que promete devolver um número e, em algum caminho, não devolveO resultado é lixo (aula Valor de Retorno).
suggest braces around empty body in an ‘if’ statement [-Wempty-body]if (nota >= 7);Um ; logo depois do if: o bloco ficou vazio (aula Compilar com gcc).
unused parameter [-Wunused-parameter]int main(int argc, char *argv[]) sem usarParâmetro recebido e ignorado (só com -Wextra).

4. Avisos que o gcc 15 já trata como erro

Alguns enganos eram só avisos nos compiladores antigos e, de tão perigosos, viraram erros a partir do gcc 14. Eles ainda mostram o nome de aviso entre colchetes, mas impedem o programa, mesmo sem -Wall:

NomeQuando aconteceExemplo de mensagem
[-Wimplicit-function-declaration]Usar uma função sem o #include dela, ou com o nome erradoerror: implicit declaration of function ‘printf’
[-Wint-conversion]Misturar número e endereço (texto num int)error: initialization of ‘int’ from ‘char *’ makes integer from pointer without a cast

Os dois aparecem, com a mensagem real, na aula Lendo Erros do Compilador. Se um livro ou curso antigo disser que "é só um aviso", agora você sabe por que o seu gcc recusa.


5. -Werror: avisos viram erros

Com -Werror, todo aviso passa a ser tratado como erro, e o programa não é criado:

$ gcc -std=c23 -Wall -Wextra -Werror igual.c -o igual
igual.c: In function ‘main’:
igual.c:5:9: error: suggest parentheses around assignment used as truth value [-Werror=parentheses]
    5 |     if (nota = 10) {
      |         ^~~~
cc1: all warnings being treated as errors
$ echo $?
1
$ gcc -std=c23 -Wall -Wextra -Werror compras.c -o compras
compras.c: In function ‘main’:
compras.c:4:9: error: unused variable ‘itens’ [-Werror=unused-variable]
    4 |     int itens = 3;
      |         ^~~~~
cc1: all warnings being treated as errors

Repare: warning: virou error:, o nome entre colchetes virou [-Werror=…], e a última linha explica: "todos os avisos estão sendo tratados como erros" (o cc1 é a parte do gcc que compila C). O Clang marca assim: error: unused variable 'itens' [-Werror,-Wunused-variable].

Quando usar? Em projetos sérios, o -Werror costuma estar ligado no sistema de compilação (aulas Makefile e CMake) e nos servidores que testam cada mudança: ninguém consegue entregar código com aviso. Para quem está aprendendo, é uma ótima disciplina: ligue-o e o compilador não deixa você "deixar para depois". A missão final desta aula usa o -Werror.

Mais avisos: -Wconversion

-Wall -Wextra é o mínimo, não o máximo. Uma opção extra muito útil é a -Wconversion, que avisa quando um valor perde parte de si numa conversão. Aqui, 2,50 × 3 dá 7,50, e o int guarda só o 7:

$ gcc -std=c23 -Wall -Wextra conversao.c -o conversao && ./conversao   « int total = preco * 3;
Total: 7 reais           « sumiram 50 centavos, e nenhum aviso
$ gcc -std=c23 -Wall -Wextra -Wconversion conversao.c -o conversao
conversao.c: In function ‘main’:
conversao.c:5:17: warning: conversion from ‘double’ to ‘int’ may change value [-Wfloat-conversion]
    5 |     int total = preco * 3;
      |                 ^~~~~

"A conversão de double para int pode mudar o valor". A aula Conversão de Tipos explica quando isso é de propósito. Outras opções que você vai ver em projetos: -Wpedantic (avisa o que não é C padrão) e -Wshadow (avisa quando um nome esconde outro, aula Escopo).


6. Por que nunca ignorar avisos

  • Os avisos apontam bugs reais. Os exemplos da seção 3 compilavam e rodavam, e todos davam resultado errado.
  • Avisos se acumulam. Um aviso "inofensivo" hoje vira dez amanhã, e o aviso importante se perde no meio deles. Com zero avisos, qualquer aviso novo salta aos olhos.
  • O compilador conhece as armadilhas da linguagem. O C tem muitas, e os avisos são décadas de experiência resumidas.
  • Corrigir na hora é barato. O mesmo engano, achado depois que o programa está nas mãos de alguém, custa muito mais.
Não "conserte" calando o compilador

Existe a opção -w (minúsculo), que desliga todos os avisos, até os do -Wall -Wextra:

$ gcc -std=c23 -Wall -Wextra -w igual.c -o igual
$                        « o aviso sumiu; o erro do programa continua lá

É apagar a luz do óleo em vez de pôr óleo. Não use. O conserto de um aviso é sempre mudar o código.

A regra do guia: compile sempre com -Wall -Wextra e só considere o programa pronto quando a compilação estiver em silêncio. As missões do editor muitas vezes exigem isso (a meta "sem avisos").


Quando dá errado

"O programa rodou, mas o resultado está errado"

O que significa: muitas vezes, o compilador sabia. Você compilou sem -Wall -Wextra, ou viu o aviso e ignorou.

Como consertar: compile de novo com -Wall -Wextra (e, para garantir, com -O2 também) e leia cada warning:.

format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘double’

O que significa: a lacuna do printf não combina com o tipo do valor (seção 3.1). O que aparece na tela é lixo, e com %s o programa pode até cair (aula Saída com printf).

Como consertar: use a lacuna que o gcc sugere na última linha do desenho.

suggest parentheses around assignment used as truth value

O que significa: um = dentro de um if (ou while). Quase sempre era ==.

Como consertar: troque por ==.

comparison of integer expressions of different signedness

O que significa: você está comparando um número que aceita negativos com um que não aceita. Se o primeiro for negativo, o resultado sai errado.

Como consertar: use o mesmo tipo dos dois lados.

is used uninitialized / may be used uninitialized

O que significa: uma variável é lida antes de receber valor (sempre, ou em algum caminho).

Como consertar: dê um valor inicial na criação: int x = 0;.

cc1: all warnings being treated as errors

O que significa: o comando tem -Werror; um aviso impediu a criação do programa.

Como consertar: corrija o aviso indicado acima dessa linha. (Tirar o -Werror só esconde o problema.)


Referência rápida

OpçãoO que faz
-WallLiga os avisos principais (sempre use)
-WextraLiga avisos extras (sempre use)
-O2Otimiza; de quebra, revela avisos como -Wmaybe-uninitialized
-WerrorTrata avisos como erros: o programa não é criado
-WconversionAvisa conversões que podem mudar o valor
-wDesliga todos os avisos (não use)
AvisoLigado porConserto típico
format ‘%…’ expects argument of type…sempre (e -Wall)A lacuna do tipo certo
unused variable-WallUse a variável ou apague-a
unused parameter-WextraTire o parâmetro ou use-o
suggest parentheses around assignment-Wall= → ==
different signedness-Wextra (no C)Mesmo tipo dos dois lados
is used uninitialized-WallValor inicial: int x = 0;
may be used uninitialized-Wall + -O2Valor inicial: int x = 0;
statement with no effect-WallProvavelmente == → =
control reaches end of non-void function-WallUm return em todos os caminhos
conversion … may change value-WconversionTipo certo, ou conversão de propósito

Exercícios

1. Ligar os avisos

Complete o comando padrão do guia:

gcc -std=c23 jogo.c -o jogo

2. Avisos como erros

Que opção faz qualquer aviso impedir a criação do programa?

gcc -std=c23 -Wall -Wextra jogo.c -o jogo

3. Corrija a condição

Complete para comparar, e não guardar:

if (pontos 100) {

4. O que acontece quando a compilação dá só um warning:?

5. Por que if (saldo < limite), com saldo = -1 (int) e limite = 10 (unsigned), deu falso?

6. Com printf("%d\n", 1.65);, o que acontece?

7. Qual é a forma certa de lidar com um aviso?

Missão final: zero avisos (com -Werror)

Missão: esta caixa compila com -Werror: com qualquer aviso, o programa nem é criado. Corrija o código da lojinha (sem tirar o -Werror!) até ele compilar e mostrar:

Estoque da lojinha
Canetas: 0
Repor canetas!

Dicas: uma variável sobrando, uma variável sem valor (as canetas começam em 0) e um = que deveria ser ==. Conserte um de cada vez, rodando entre um e outro.

#include <stdio.h>

int main(void) {
    int cadernos = 12;
    int canetas;
    printf("Estoque da lojinha\n");
    printf("Canetas: %d\n", canetas);
    if (canetas = 0) {
        printf("Repor canetas!\n");
    }
    return 0;
}
#include <stdio.h>

int main(void) {
    int canetas = 0;
    printf("Estoque da lojinha\n");
    printf("Canetas: %d\n", canetas);
    if (canetas == 0) {
        printf("Repor canetas!\n");
    }
    return 0;
}

Resumo

  • Um aviso (warning:) não impede a criação do programa, mas quase sempre aponta um engano real.
  • O gcc vem com quase todos os avisos desligados. -Wall -Wextra os ligam: use sempre. Em C, alguns importantes (como o -Wsign-compare) só vêm com o -Wextra.
  • Avisos que salvam programas: formato errado no printf, = no lugar de ==, int comparado com unsigned, variável sem valor, variável não usada.
  • Alguns avisos (may be used uninitialized) só aparecem com -O2: compile com ele de vez em quando.
  • No gcc 15, implicit declaration of function e int-conversion já são erros.
  • -Werror transforma avisos em erros; -Wconversion liga mais avisos; -w esconde todos (não use).
  • A meta é zero avisos: o conserto é sempre mudar o código.
  • Próximo passo: Variáveis, onde começam os programas que guardam e mudam valores.