Questões de segurança de tipos
Riscos dos argumentos variáveis.
Questões de segurança de tipos é uma aula grátis de C Academy no CoddyKit. Esta é a aula 3 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de C Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de C Academy inclui 4 aulas no total.
Argumentos variádicos ignoram a verificação de tipos
Funções C normais verificam se os argumentos correspondem aos tipos dos parâmetros. Os argumentos variádicos ignoram completamente essa verificação.
O compilador não consegue verificar o que é passado depois de ..., o que torna os erros fáceis de cometer e perigosos.
#include <stdio.h>
#include <stdarg.h>
int add(int n, ...) {
va_list a; va_start(a, n);
int s = 0;
for (int i = 0; i < n; i++) s += va_arg(a, int);
va_end(a);
return s;
}
int main(void) {
printf("%d\n", add(2, 3, 4));
return 0;
}Tipo incorreto em va_arg
Se você ler um argumento com o tipo incorreto, o resultado será comportamento indefinido.
Passar um int e lê-lo como double reinterpretará bytes sem relação entre si e produzirá lixo ou uma falha.
#include <stdio.h>
#include <stdarg.h>
int read_int(int n, ...) {
va_list a; va_start(a, n);
int v = va_arg(a, int);
va_end(a);
return v;
}
int main(void) {
printf("%d\n", read_int(1, 100));
return 0;
}Incompatibilidades na cadeia de formato
Em funções no estilo de printf, um especificador incorreto é um erro clássico. printf("%d", 3.14) lê um double como se fosse um int.
Compiladores modernos avisam sobre incompatibilidades literais, mas não conseguem detectar cadeias de formato criadas durante a execução.
#include <stdio.h>
int main(void) {
double pi = 3.14;
printf("%f\n", pi);
return 0;
}Surpresas das promoções de inteiros
Tipos pequenos são promovidos para int na parte variádica. Portanto, mesmo que você passe um char, deverá lê-lo de volta como um int.
Lê-lo como char com va_arg(a, char) é comportamento indefinido.
#include <stdio.h>
#include <stdarg.h>
void show(int n, ...) {
va_list a; va_start(a, n);
int c = va_arg(a, int);
printf("char is %c\n", c);
va_end(a);
}
int main(void) {
show(1, 'A');
return 0;
}Float torna-se double
Um argumento float sempre é promovido para double em argumentos variádicos. Você deve lê-lo como double, nunca como float.
Esse é um dos erros variádicos mais comuns.
#include <stdio.h>
#include <stdarg.h>
void show(int n, ...) {
va_list a; va_start(a, n);
double d = va_arg(a, double);
printf("%.2f\n", d);
va_end(a);
}
int main(void) {
float f = 1.5f;
show(1, f);
return 0;
}Lendo argumentos demais
Se o seu código chamar va_arg mais vezes do que o número de argumentos fornecidos pelo chamador, você lerá lixo da pilha.
É por isso que uma contagem precisa ou uma sentinela é essencial.
#include <stdio.h>
#include <stdarg.h>
int sum(int n, ...) {
va_list a; va_start(a, n);
int s = 0;
for (int i = 0; i < n; i++) s += va_arg(a, int);
va_end(a);
return s;
}
int main(void) {
printf("%d\n", sum(3, 1, 2, 3));
return 0;
}Sentinelas com ponteiro NULL exigem cuidado
Usar NULL como sentinela é arriscado: em algumas plataformas, NULL é 0 como um int, o que tem tamanho diferente de um ponteiro.
Faça a conversão explicitamente, como em (char *)NULL, para garantir que o tipo correto seja colocado.
#include <stdio.h>
#include <stdarg.h>
void print_all(const char *first, ...) {
va_list a; va_start(a, first);
const char *s = first;
while (s) { printf("%s\n", s); s = va_arg(a, const char *); }
va_end(a);
}
int main(void) {
print_all("a", "b", (char *)NULL);
return 0;
}Atributos de formato do compilador
GCC e Clang oferecem __attribute__((format(printf, 1, 2))) para informar ao compilador que sua função usa formatação no estilo de printf.
Assim, ele verifica suas cadeias de formato durante a compilação e detecta muitos erros.
#include <stdio.h>
#include <stdarg.h>
void logf(const char *fmt, ...)
__attribute__((format(printf, 1, 2)));
void logf(const char *fmt, ...) {
va_list a; va_start(a, fmt);
vprintf(fmt, a);
va_end(a);
}
int main(void) {
logf("%d items\n", 3);
return 0;
}Prefira alternativas mais seguras
Como os argumentos variádicos estão sujeitos a erros, prefira projetos com segurança de tipos quando possível: passe uma matriz explícita, uma struct ou parâmetros fixos.
Reserve os argumentos variádicos para necessidades genuínas semelhantes às de printf.
#include <stdio.h>
int sum_array(const int *a, int n) {
int s = 0;
for (int i = 0; i < n; i++) s += a[i];
return s;
}
int main(void) {
int nums[] = {1, 2, 3, 4};
printf("%d\n", sum_array(nums, 4));
return 0;
}Documente o contrato
Como o compilador não consegue impor os tipos dos argumentos variádicos, uma documentação clara é sua proteção.
Informe exatamente quais tipos e quantos argumentos o chamador deve fornecer, além de como a lista termina.
#include <stdio.h>
#include <stdarg.h>
/* sum_ints(n, ...): pass exactly n int values */
int sum_ints(int n, ...) {
va_list a; va_start(a, n);
int s = 0;
for (int i = 0; i < n; i++) s += va_arg(a, int);
va_end(a);
return s;
}
int main(void) {
printf("%d\n", sum_ints(2, 5, 5));
return 0;
}Testando minuciosamente
Como os erros podem permanecer ocultos, teste as funções variádicas com muitas quantidades e tipos de argumentos.
Casos-limite, como zero argumentos ou a quantidade máxima, frequentemente revelam erros.
#include <stdio.h>
#include <stdarg.h>
int sum(int n, ...) {
va_list a; va_start(a, n);
int s = 0;
for (int i = 0; i < n; i++) s += va_arg(a, int);
va_end(a);
return s;
}
int main(void) {
printf("%d\n", sum(0));
printf("%d\n", sum(1, 9));
return 0;
}Verificação rápida
Teste sua compreensão dos riscos de tipos em argumentos variádicos.
Recapitulação
Você aprendeu os perigos das funções variádicas:
- O compilador não verifica os tipos dos argumentos variádicos.
- Tipos incorretos, quantidades incorretas e sentinelas inadequadas causam comportamento indefinido.
- Lembre-se das promoções: inteiros pequenos tornam-se
intefloattorna-sedouble. - Use atributos de formato do compilador, documente o contrato e prefira alternativas com segurança de tipos quando possível.
Perguntas Frequentes
A aula “Questões de segurança de tipos” é grátis?
Sim — o texto completo de “Questões de segurança de tipos” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de C Academy, atualize para CoddyKit PRO. O curso de C Academy inclui 4 aulas no total.
O que vou aprender em “Questões de segurança de tipos”?
Riscos dos argumentos variáveis. Você pratica C Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar C Academy?
Nenhuma experiência prévia é necessária. C Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 3 de 4.
Quanto tempo leva a aula “Questões de segurança de tipos”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de C Academy?
Sim. Cada aula de C Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- As macros stdarg
- Escrevendo funções semelhantes a printf
- Questões de segurança de tipos
- Exemplos práticos