C Conversão de Tipos (cast)

Em C, todo valor tem um tipo, e muitas vezes um valor de um tipo precisa virar outro: um int entra numa conta com um double, um número com vírgula é guardado numa variável inteira, uma letra vira o seu código. Às vezes o C faz essa conversão sozinho, sem avisar; às vezes você precisa pedir, com um cast. Nesta aula você vai ver as duas, entender por que a média de 8 e 9 sai 8.00 em vez de 8.50, e conhecer a conversão mais traiçoeira do C: a que faz -1 ficar maior que 0.

Você vai aprender
  • O que o C converte sozinho (conversão implícita) e o que se perde no caminho.
  • Por que um double guardado num int é cortado, não arredondado.
  • A promoção: por que char + char dá um int.
  • Como pedir avisos das conversões perigosas com -Wconversion.
  • O cast, (double)soma / alunos, e por que a posição dele muda o resultado.
  • Como arredondar de verdade.
  • Letras e números: 'A' + 1 e '7' - '0'.
  • A surpresa do signed com unsigned: -1 > 0u é verdade.

Todos os programas desta aula foram compilados com o gcc 15.2 na máquina fictícia da Ana (usuária ana, computador notebook), na pasta ~/c, com o comando padrão do guia: gcc -std=c23 -Wall -Wextra arquivo.c -o programa. Você pode repetir cada um no editor do guia, que compila C de verdade no navegador.


A ideia: passar água de um copo para outro

Imagine três recipientes: um copinho de café, um copo comum e uma jarra. Passar a água do copinho para a jarra é tranquilo: cabe tudo, sobra espaço. Passar da jarra para o copinho é outra história: a água transborda e você perde uma parte.

Os tipos do C são esses recipientes. Um int cabe inteiro num double; um double com vírgula não cabe num int, e a parte depois da vírgula "transborda". O problema é que o C, na maioria das vezes, derrama a água sem avisar.

ConversãoComparaçãoO que acontece
int → doublecopinho → jarraSeguro: 7 vira 7.0.
double → intjarra → copinhoPerde a parte fracionária: 9.99 vira 9.
int → charcopo → copinhoSe o número for grande, sobra lixo: 300 vira 44.
int → unsignedcopo → copo sem fundo negativoNegativos viram números enormes: -1 vira 4294967295.

1. Conversão implícita: o C converte sozinho

"Implícita" quer dizer "sem ninguém pedir". Ela acontece em dois lugares: quando você guarda um valor numa variável de outro tipo e quando você mistura tipos numa conta.

#include <stdio.h>

int main(void) {
    int caixas = 3;
    double peso = 2.5;
    double total = caixas * peso;
    int inteiro = 9.99;
    int negativo = -9.99;
    double d = 7;
    printf("total = %.2f\n", total);
    printf("inteiro = %d\n", inteiro);
    printf("negativo = %d\n", negativo);
    printf("d = %f\n", d);
    return 0;
}
$ gcc -std=c23 -Wall -Wextra implicita.c -o implicita
$ ./implicita
total = 7.50
inteiro = 9
negativo = -9
d = 7.000000
caixas * peso
Uma conta com um int (3) e um double (2.5). Antes de multiplicar, o C converte o 3 para 3.0, e o resultado é um double: 7.5. Nada se perde.
int inteiro = 9.99;
Guardar um double num int: a parte depois do ponto é jogada fora. Fica 9, e não 10. Isso se chama truncamento ("corte").
int negativo = -9.99;
Com negativos, o corte também vai "em direção ao zero": -9.99 vira -9 (e não -10).
double d = 7;
Guardar um int num double: 7 vira 7.0, sem perda.

Repare: o gcc compilou sem nenhum aviso, mesmo com -Wall -Wextra, e o 9.99 virou 9 calado. O Clang do editor é mais atento quando o número está escrito direto no código e avisa mesmo sem opções extras: implicit conversion from 'double' to 'int' changes value from 9.99 to 9 [-Wliteral-conversion] ("conversão implícita de double para int muda o valor de 9.99 para 9").

A regra das contas: o tipo "maior" ganha

Quando uma conta mistura dois tipos, o C converte o "menor" para o "maior" antes de calcular. A ordem, do menor para o maior, é mais ou menos esta:

int  →  unsigned int  →  long  →  long long  →  float  →  double  →  long double
  • int com double → a conta é feita em double.
  • int com long long → a conta é feita em long long.
  • int com int → a conta é feita em int, e o resultado é int, mesmo que você o guarde num double depois (seção 4).
  • int com unsigned int → a conta é feita em unsigned, e aí moram surpresas (seção 7).

A promoção: tipos pequenos viram int

Tem mais uma regra: char, short e bool nunca entram numa conta do jeito que são. Antes de qualquer conta, eles são promovidos a int:

#include <stdio.h>

int main(void) {
    char a = 100;
    char b = 100;
    int soma = a + b;
    char c = a + b;
    printf("%d %d %zu\n", soma, c, sizeof(a + b));
    return 0;
}
$ gcc -std=c23 -Wall -Wextra promo.c -o promo
$ ./promo
200 -56 4
  • soma deu 200, apesar de um char só ir até 127: a conta a + b foi feita em int, onde 200 cabe.
  • sizeof(a + b) deu 4: o resultado da conta é um int, não um char (aula Tamanho dos Tipos).
  • c deu -56: o 200 foi guardado de volta num char, que não o comporta. Sobraram só os 8 bits de baixo, que num char com sinal valem −56 (200 − 256). A água transbordou.

2. Pedir avisos: -Wconversion

Como o gcc fica calado nas conversões que perdem informação, existe uma opção para ligar esses avisos: -Wconversion. Ela não faz parte do -Wall nem do -Wextra, porque costuma avisar muito em código antigo (a aula Avisos fala das opções de aviso).

#include <stdio.h>

int main(void) {
    double preco = 9.99;
    int reais = preco;
    int nota = 300;
    char c = nota;
    printf("%d %d\n", reais, c);
    return 0;
}
$ gcc -std=c23 -Wall -Wextra perdas.c -o perdas      « nenhum aviso
$ ./perdas
9 44
$ gcc -std=c23 -Wall -Wextra -Wconversion perdas.c -o perdas
perdas.c: In function ‘main’:
perdas.c:5:17: warning: conversion from ‘double’ to ‘int’ may change value [-Wfloat-conversion]
    5 |     int reais = preco;
      |                 ^~~~~
perdas.c:7:14: warning: conversion from ‘int’ to ‘char’ may change value [-Wconversion]
    7 |     char c = nota;
      |              ^~~~
conversion from ‘double’ to ‘int’
"Conversão de double para int": o compilador aponta exatamente onde o tipo muda.
may change value
"Pode mudar o valor." Ele diz "pode" porque preco é uma variável: o compilador não sabe se ela terá parte fracionária. Com um número escrito direto (int x = 9.99;), ele diz changes value from ‘9.9900000000000002e+0’ to ‘9’, "muda o valor de 9.99 para 9".
[-Wfloat-conversion]
A parte do -Wconversion que vigia números com vírgula virando inteiros.
from ‘int’ to ‘char’
O 300 não cabe num char: de fato, virou 44 (300 − 256).

No Clang do editor, as mensagens são implicit conversion turns floating-point number into integer: 'double' to 'int' [-Wfloat-conversion] ("a conversão implícita transforma número com vírgula em inteiro") e implicit conversion loses integer precision: 'int' to 'char' [-Wimplicit-int-conversion] ("a conversão implícita perde precisão de inteiro").

Ligue o -Wconversion de vez em quando

Para os exercícios do guia, o comando padrão basta. Mas em programas que fazem contas com dinheiro ou medidas, compile de vez em quando com -Wconversion e leia os avisos: cada um é um lugar onde algo pode estar se perdendo. Os que forem de propósito, você marca com um cast (a próxima seção), e o aviso some.


3. Conversão explícita: o cast

"Explícita" quer dizer "pedida por escrito". Para converter um valor de propósito, escreva o tipo desejado entre parênteses na frente dele. Isso se chama cast (do inglês, "moldar", como se põe metal derretido numa fôrma):

#include <stdio.h>

int main(void) {
    double preco = 12.50;
    int reais = (int)preco;
    int centavos = (int)((preco - reais) * 100);
    printf("%d reais e %d centavos\n", reais, centavos);
    printf("%f\n", (double)7);
    return 0;
}
(int)preco
"Converta preco para int." O resultado é 12 (o corte de sempre). O cast não muda a variável preco, que continua 12.50: ele produz um valor novo, convertido.
(int)((preco - reais) * 100)
Primeiro a conta entre parênteses: (12.50 − 12) × 100 = 50.0, um double. Depois o cast o transforma em 50. Os parênteses em volta da conta são necessários: sem eles, o (int) valeria só para o preco (seção 4 mostra por quê).
(double)7
Converte o inteiro 7 para 7.0.
$ gcc -std=c23 -Wall -Wextra -Wconversion cast.c -o cast
$ ./cast
12 reais e 50 centavos
7.000000

Com o cast, o resultado é o mesmo da conversão implícita, mas agora nenhum aviso, nem com -Wconversion: o cast diz ao compilador (e a quem lê) "eu sei que vou perder a parte fracionária, é de propósito".

O cast não conserta valores

Um cast só muda o tipo. Ele não arredonda ((int)9.99 é 9) e não faz caber o que não cabe ((char)300 continua virando 44). E não transforma texto em número: (int)"42" não dá 42 (para isso existem funções próprias, aula Texto ↔ Número).

Missão: esta caixa compila com -Wconversion ligado. Rode e veja o aviso: a conversão de double para int está escondida. Ela é de propósito (queremos só a parte inteira), então deixe isso por escrito com um cast. O programa deve continuar mostrando as mesmas duas linhas, agora sem nenhum aviso.

#include <stdio.h>

int main(void) {
    double pizza = 3.5;
    int pedacos = pizza;
    printf("Cada fatia: %d pedaços\n", pedacos);
    printf("Sobra de pizza: %.2f\n", pizza - pedacos);
    return 0;
}
#include <stdio.h>

int main(void) {
    double pizza = 3.5;
    int pedacos = (int)pizza;
    printf("Cada fatia: %d pedaços\n", pedacos);
    printf("Sobra de pizza: %.2f\n", pizza - pedacos);
    return 0;
}

4. Divisão inteira × divisão real

Este é o lugar onde a conversão de tipos mais pega quem está começando. A Ana tirou 8 e 9; a soma é 17 e a média deveria ser 8.5:

#include <stdio.h>

int main(void) {
    int soma = 17;
    int alunos = 2;
    double media1 = soma / alunos;
    double media2 = (double)soma / alunos;
    double media3 = (double)(soma / alunos);
    double media4 = soma / (double)alunos;
    double media5 = soma * 1.0 / alunos;
    printf("%.2f %.2f %.2f %.2f %.2f\n", media1, media2, media3, media4, media5);
    return 0;
}
$ gcc -std=c23 -Wall -Wextra media.c -o media
$ ./media
8.00 8.50 8.00 8.50 8.50
LinhaPasso a passoResultado
soma / alunosint / int → divisão inteira: 17 / 2 = 8 (o resto some). Só depois o 8 vira 8.0 para entrar no double.8.00 ✗
(double)soma / alunosO cast vale só para soma: 17.0. Agora é double / int → o alunos vira 2.0 e a divisão é real: 8.5.8.50 ✓
(double)(soma / alunos)Os parênteses fazem a divisão inteira primeiro (8) e só depois convertem: 8.0. Cast tarde demais.8.00 ✗
soma / (double)alunosBasta um dos lados ser double.8.50 ✓
soma * 1.0 / alunosUm truque antigo: multiplicar por 1.0 (um double) transforma a conta em real.8.50 ✓

Duas lições. Primeira: o tipo da variável que recebe o resultado (double media1) não muda como a conta é feita; o C olha só os tipos dentro da conta. Segunda: o cast vale para o que está logo depois dele. (double)soma / alunos é lido como ((double)soma) / alunos, porque o cast tem prioridade sobre a divisão (aula Precedência). Mais sobre a divisão inteira em Operadores Aritméticos.

Missão: a média das notas 8 e 9 está saindo 8.00. Use um cast (double) no lugar certo para o programa mostrar Média: 8.50, sem mudar o tipo das variáveis soma e quantidade.

#include <stdio.h>

int main(void) {
    int soma = 8 + 9;
    int quantidade = 2;
    double media = soma / quantidade;
    printf("Média: %.2f\n", media);
    return 0;
}
#include <stdio.h>

int main(void) {
    int soma = 8 + 9;
    int quantidade = 2;
    double media = (double)soma / quantidade;
    printf("Média: %.2f\n", media);
    return 0;
}

5. E se eu quiser arredondar?

Converter para int sempre corta. Para arredondar, há dois caminhos:

#include <stdio.h>
#include <math.h>

int main(void) {
    double x = 2.7;
    double y = -2.7;
    printf("%d %d\n", (int)x, (int)y);
    printf("%d %d\n", (int)(x + 0.5), (int)(y + 0.5));
    printf("%.0f %.0f\n", round(x), round(y));
    printf("%ld %ld\n", lround(x), lround(y));
    return 0;
}

As funções round e lround moram na biblioteca de matemática (math.h, aula Matemática). No gcc, essa biblioteca precisa ser pedida com -lm no fim do comando. Sem ela:

$ gcc -std=c23 -Wall -Wextra arred.c -o arred
/usr/bin/x86_64-linux-gnu-ld.bfd: /tmp/cc7SBp3h.o: na função "main":
arred.c:(.text+0x99): referência não definida para "round"
/usr/bin/x86_64-linux-gnu-ld.bfd: arred.c:(.text+0xac): referência não definida para "round"
/usr/bin/x86_64-linux-gnu-ld.bfd: arred.c:(.text+0xdd): referência não definida para "lround"
/usr/bin/x86_64-linux-gnu-ld.bfd: arred.c:(.text+0xee): referência não definida para "lround"
collect2: error: ld returned 1 exit status
$ gcc -std=c23 -Wall -Wextra arred.c -o arred -lm
$ ./arred
2 -2
3 -2
3 -3
3 -3
  • O erro veio do ligador (ld), que no laboratório fala português: referência não definida para "round" (em inglês, undefined reference to 'round') quer dizer "não achei o código da função round". O -lm ("ligue a biblioteca m, de matemática") resolve. No editor do guia, a matemática já vem junto e não precisa de -lm.
  • (int)x e (int)y: o corte de sempre, 2 e −2.
  • (int)(x + 0.5): o truque de somar meio antes de cortar funciona para positivos (2.7 + 0.5 = 3.2 → 3), mas falha com negativos (−2.7 + 0.5 = −2.2 → −2, e o certo era −3).
  • round(x) arredonda certo nos dois casos, mas devolve um double (por isso %.0f). lround(x) arredonda e já devolve um long (por isso %ld).

Use lround (ou round) para arredondar. Para só mostrar um número arredondado, nem precisa converter: printf("%.0f", x) já arredonda na hora de escrever (veja Formatos do printf).


6. Letras e números: char ↔ int

Para o C, um char é um número pequeno: o código da letra na tabela ASCII (aula Caracteres). Por isso dá para fazer contas com letras:

#include <stdio.h>

int main(void) {
    char letra = 'A';
    char proxima = letra + 1;
    char digito = '7';
    int valor = digito - '0';
    printf("%c %c %d\n", letra, proxima, proxima);
    printf("'%c' vale %d, e '%c' - '0' = %d\n", digito, digito, digito, valor);
    printf("%c\n", 'a' - 32);
    return 0;
}
$ gcc -std=c23 -Wall -Wextra letras.c -o letras
$ ./letras
A B 66
'7' vale 55, e '7' - '0' = 7
A
letra + 1
'A' é 65; mais 1 dá 66, que é o código do 'B'. As letras estão em ordem na tabela.
%c e %d com o mesmo valor
O formato decide se você vê a letra (B) ou o número (66). O valor guardado é o mesmo.
digito - '0'
O caractere '7' não vale 7: vale 55, o código dele. Mas os algarismos também estão em ordem ('0' é 48, '1' é 49…), então '7' - '0' = 55 − 48 = 7. É o jeito clássico de transformar um algarismo digitado no seu valor.
'a' - 32
As minúsculas ficam 32 posições depois das maiúsculas: 'a' (97) − 32 = 65 = 'A'. Funciona, mas a forma certa de trocar maiúscula e minúscula é toupper/tolower, da aula Classificar Caracteres, que também lida com o que não é letra.

7. A surpresa: signed com unsigned

Quando uma conta ou comparação mistura um int (com sinal, signed) com um unsigned int (sem sinal), a regra da seção 1 manda converter o int para unsigned. E um negativo convertido para unsigned vira um número enorme:

#include <stdio.h>

int main(void) {
    int saldo = -1;
    unsigned int limite = 0;
    if (saldo > limite) {
        printf("-1 é maior que 0?!\n");
    } else {
        printf("tudo normal\n");
    }
    printf("%d\n", -1 > 0u);
    printf("%u\n", (unsigned int)saldo);
    return 0;
}
$ gcc -std=c23 -Wall -Wextra sinal.c -o 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) {
      |               ^
sinal.c:11:23: warning: comparison of integer expressions of different signedness: ‘int’ and ‘unsigned int’ [-Wsign-compare]
   11 |     printf("%d\n", -1 > 0u);
      |                       ^
$ ./sinal
-1 é maior que 0?!
1
4294967295
saldo > limite
Para comparar, o C converteu o saldo (−1) para unsigned. O resultado é 4294967295, o maior unsigned int, que é mesmo maior que 0. Por isso o if (aula if e else) escolheu o caminho errado.
-1 > 0u
O u no fim de 0u faz dele um unsigned. A comparação dá 1, que em C quer dizer "verdadeiro" (aula Operadores de Comparação).
(unsigned int)saldo
O cast mostra o valor convertido: 4294967295. Os bits de −1 são todos "1", e lidos sem sinal formam o maior número possível (aula Inteiros).
comparison of integer expressions of different signedness
"Comparação de inteiros com sinais diferentes." O aviso -Wsign-compare vem com o -Wextra, mais um motivo para nunca compilar sem ele. O Clang diz comparison of integers of different signs: 'int' and 'unsigned int'.

Onde isso aparece na vida real: o resultado do sizeof e do strlen é size_t, que é unsigned. Comparar um int negativo com eles dá exatamente essa surpresa. Conserto: não misture. Se um valor pode ser negativo, compare-o primeiro com 0 (if (saldo < 0 || …)) ou use o mesmo tipo dos dois lados.


Formas diferentes: qual usar

SituaçãoFormasUse
Dividir dois int e querer a vírgula(double)a / b, a / (double)b, a * 1.0 / b(double)a / b: deixa a intenção clara. Nunca (double)(a / b).
Ficar só com a parte inteira de um doubleint n = x; ou int n = (int)x;(int)x: o mesmo resultado, mas por escrito e sem aviso do -Wconversion.
Arredondar(int)(x + 0.5), round(x), lround(x)lround(x) (ou round). O truque do 0.5 falha com negativos.
Só mostrar arredondadoconverter, ou %.0f / %.2fprintf("%.2f", x): não precisa converter nada.
Algarismo ('7') → número (7)c - '0'c - '0'. Para textos inteiros ("427"), strtol (aula Texto ↔ Número).
Comparar com sizeof / strlenmisturar int e size_tUse size_t nas suas variáveis também, ou confira o negativo antes.

Quando dá errado

A média (ou a porcentagem) sai sem a parte decimal: 8.00 em vez de 8.50

O que significa: a divisão foi feita entre dois int, e o resto foi descartado antes de o resultado chegar ao double.

Como consertar: converta um dos lados antes da divisão: (double)soma / n. Confira que o cast não está em volta da divisão inteira.

O valor foi cortado: 9.99 virou 9, sem aviso

O que significa: um double foi guardado num int e o C truncou em silêncio.

Como consertar: se o valor tem centavos, a variável deveria ser double. Se você quer um inteiro, decida: cortar ((int)x) ou arredondar (lround(x)). Para achar esses lugares, compile com -Wconversion.

warning: conversion from ‘double’ to ‘int’ may change value [-Wfloat-conversion]

O que significa: com -Wconversion ligado, o gcc mostra uma conversão que pode perder a parte fracionária.

Como consertar: se foi sem querer, troque o tipo da variável. Se foi de propósito, escreva o cast: int n = (int)x;.

warning: comparison of integer expressions of different signedness: ‘int’ and ‘unsigned int’

O que significa: uma comparação mistura com sinal e sem sinal. Se o lado com sinal for negativo, o resultado vai estar errado.

Como consertar: use o mesmo tipo dos dois lados (por exemplo, size_t para contadores comparados com sizeof) ou trate o negativo antes.

referência não definida para "round" (undefined reference to 'round')

O que significa: o ligador não achou a função de math.h.

Como consertar: acrescente -lm no fim do comando do gcc: gcc … arred.c -o arred -lm.


Referência

EscritaResultadoPor quê
int n = 9.99;9Conversão implícita: corta a parte fracionária.
int n = -9.99;-9O corte vai em direção ao zero.
double d = 7;7.0int → double não perde nada.
3 * 2.57.5 (double)Na conta, o tipo "maior" ganha.
17 / 28int / int = divisão inteira.
(double)17 / 28.5Cast antes da divisão.
(double)(17 / 2)8.0Cast depois da divisão: tarde demais.
(int)2.7 / lround(2.7)2 / 3Cast corta; lround arredonda (precisa de -lm no gcc).
char a = 100, b = 100; a + b200 (int)Promoção: char vira int nas contas.
char c = 300;44Não cabe: sobram os 8 bits de baixo.
'A' + 166 ('B')Letra é número.
'7' - '0'7Algarismo → valor.
-1 > 0u1 (verdadeiro!)O −1 vira unsigned: 4294967295.
-Wconversionavisos de conversões que perdem valorNão vem no -Wall nem no -Wextra.
-Wsign-compareaviso de comparação com sinais diferentesVem no -Wextra.

Exercícios

1. Converta de propósito

Complete com o cast que fica só com a parte inteira de altura:

int metros = altura;

2. Divisão real

Complete para que pct receba 37.5 (e não 37), com acertos = 3 e total = 8:

double pct = acertos / total * 100;

3. Do algarismo ao número

Complete para que n valha 5 quando c for o caractere '5':

int n = c - ;

4. Quanto vale x depois de int x = 7.8;?

5. Com int a = 7, b = 2;, qual expressão dá 3.5?

6. Por que -1 > 0u é verdadeiro em C?

Missão final: a conta do restaurante

Missão: a Ana e três amigos gastaram R$ 87 no restaurante e vão dividir por 4. Complete as três contas (use um cast em cada uma) para a saída ficar como abaixo, sem avisos. Dica: a primeira é uma divisão real; a segunda corta os centavos; a terceira arredonda (como o valor é positivo, o truque de somar 0.5 serve, ou use lround de math.h).

Cada um paga: R$ 21.75
Sem os centavos: R$ 21
Arredondado: R$ 22
#include <stdio.h>

int main(void) {
    int conta = 87;
    int pessoas = 4;

    double cada = conta / pessoas;   // conserte: está dando 21.00
    int sem_centavos = 0;            // a parte inteira de cada
    int arredondado = 0;             // cada, arredondado

    printf("Cada um paga: R$ %.2f\n", cada);
    printf("Sem os centavos: R$ %d\n", sem_centavos);
    printf("Arredondado: R$ %d\n", arredondado);
    return 0;
}
#include <stdio.h>

int main(void) {
    int conta = 87;
    int pessoas = 4;

    double cada = (double)conta / pessoas;
    int sem_centavos = (int)cada;
    int arredondado = (int)(cada + 0.5);

    printf("Cada um paga: R$ %.2f\n", cada);
    printf("Sem os centavos: R$ %d\n", sem_centavos);
    printf("Arredondado: R$ %d\n", arredondado);
    return 0;
}

Resumo

  • O C converte tipos sozinho (implícita) ao guardar um valor numa variável de outro tipo e ao misturar tipos numa conta. Na conta, o tipo "maior" ganha; char e short são promovidos a int.
  • double → int corta a parte fracionária, em direção ao zero (9.99 → 9; −9.99 → −9), sem aviso no gcc. O -Wconversion liga esses avisos.
  • O cast (tipo)valor converte de propósito: não muda a variável, não arredonda e vale só para o que vem logo depois.
  • int / int é divisão inteira. Para a vírgula, converta antes: (double)a / b, nunca (double)(a / b).
  • Para arredondar, lround/round (com -lm no gcc); o truque do + 0.5 falha com negativos. Para só mostrar, %.2f.
  • Letras são números: 'A' + 1 é 'B', '7' - '0' é 7.
  • Misturar int com unsigned converte o negativo num número enorme: -1 > 0u é verdade. O -Wextra avisa com -Wsign-compare.