0Pricing
C Academy · Aula

Escrevendo funções semelhantes a printf

Argumentos variáveis.

Escrevendo funções semelhantes a printf é uma aula grátis de C Academy no CoddyKit. Esta é a aula 2 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.

Funções que recebem uma cadeia de formato

O uso mais poderoso de argumentos variádicos é criar funções no estilo de printf que interpretam uma cadeia de formato.

O formato informa à função quantos argumentos vêm depois e qual é o tipo de cada um.

#include <stdio.h>
#include <stdarg.h>

void myprint(const char *fmt, ...) {
    printf("format was: %s\n", fmt);
}

int main(void) {
    myprint("%d items\n", 5);
    return 0;
}

Percorrendo a cadeia de formato

Examine o formato caractere por caractere. Quando encontrar um %, o caractere seguinte será um especificador de conversão que informa qual tipo deve ser lido.

Todo o restante é impresso literalmente.

#include <stdio.h>
#include <stdarg.h>

void scan(const char *fmt) {
    for (const char *p = fmt; *p; p++) {
        if (*p == '%') printf("[spec:%c]", *(p+1));
        else putchar(*p);
    }
    putchar('\n');
}

int main(void) {
    scan("x=%d y=%s");
    return 0;
}

Lendo o tipo correspondente

Quando o especificador for %d, leia um int. Para %s, leia um char *. O formato deve corresponder exatamente aos argumentos reais.

#include <stdio.h>
#include <stdarg.h>

void mini(const char *fmt, ...) {
    va_list args;
    va_start(args, fmt);
    for (const char *p = fmt; *p; p++) {
        if (*p == '%' && *(p+1) == 'd') {
            printf("%d", va_arg(args, int));
            p++;
        } else putchar(*p);
    }
    va_end(args);
}

int main(void) {
    mini("count=%d\n", 42);
    return 0;
}

Lidando com vários especificadores

Amplie o analisador para lidar com várias conversões. Adicione casos para %d, %s e %c, lendo o tipo correto em cada caso.

#include <stdio.h>
#include <stdarg.h>

void fmt_print(const char *fmt, ...) {
    va_list args;
    va_start(args, fmt);
    for (const char *p = fmt; *p; p++) {
        if (*p != '%') { putchar(*p); continue; }
        p++;
        if (*p == 'd') printf("%d", va_arg(args, int));
        else if (*p == 's') printf("%s", va_arg(args, char *));
        else if (*p == 'c') putchar(va_arg(args, int));
    }
    va_end(args);
}

int main(void) {
    fmt_print("%s is %d\n", "age", 30);
    return 0;
}

Escapando o sinal de porcentagem

Funções de formato reais tratam %% como um sinal de porcentagem literal. Adicione um caso para que os usuários possam imprimir um % real.

#include <stdio.h>
#include <stdarg.h>

void fp(const char *fmt, ...) {
    va_list args;
    va_start(args, fmt);
    for (const char *p = fmt; *p; p++) {
        if (*p == '%') {
            p++;
            if (*p == '%') putchar('%');
            else if (*p == 'd') printf("%d", va_arg(args, int));
        } else putchar(*p);
    }
    va_end(args);
}

int main(void) {
    fp("%d%% done\n", 75);
    return 0;
}

Encaminhando para vprintf

Muitas vezes, você não quer reimplementar a formatação. A biblioteca padrão oferece vprintf, que recebe uma va_list diretamente.

Sua função de encapsulamento apenas repassa os argumentos.

#include <stdio.h>
#include <stdarg.h>

void logline(const char *fmt, ...) {
    va_list args;
    va_start(args, fmt);
    vprintf(fmt, args);
    va_end(args);
}

int main(void) {
    logline("value = %d, name = %s\n", 7, "box");
    return 0;
}

Adicionando um prefixo

A abordagem com vprintf facilita adicionar comportamentos ao redor da formatação padrão, como imprimir uma etiqueta antes de cada mensagem.

#include <stdio.h>
#include <stdarg.h>

void info(const char *fmt, ...) {
    printf("[INFO] ");
    va_list args;
    va_start(args, fmt);
    vprintf(fmt, args);
    va_end(args);
}

int main(void) {
    info("server started on port %d\n", 8080);
    return 0;
}

Escrevendo em um buffer com vsnprintf

Para formatar em uma cadeia de caracteres em vez de imprimir, use vsnprintf(buf, size, fmt, args).

Ela é limitada por size, evitando estouros, e sempre adiciona um terminador nulo.

#include <stdio.h>
#include <stdarg.h>

void format_into(char *buf, size_t n, const char *fmt, ...) {
    va_list args;
    va_start(args, fmt);
    vsnprintf(buf, n, fmt, args);
    va_end(args);
}

int main(void) {
    char out[64];
    format_into(out, sizeof(out), "id-%d", 123);
    printf("%s\n", out);
    return 0;
}

Retornando um comprimento

vsnprintf retorna o número de caracteres que teria sido escrito. Você pode usar esse valor para detectar truncamento ou dimensionar um buffer.

#include <stdio.h>
#include <stdarg.h>

int build(char *buf, size_t n, const char *fmt, ...) {
    va_list args;
    va_start(args, fmt);
    int len = vsnprintf(buf, n, fmt, args);
    va_end(args);
    return len;
}

int main(void) {
    char b[10];
    int needed = build(b, sizeof(b), "%d-%d", 11, 22);
    printf("%s (needed %d)\n", b, needed);
    return 0;
}

Escolhendo sua abordagem

Há duas estratégias: analisar o formato por conta própria para ter controle total ou encaminhá-lo para vprintf/vsnprintf em busca de correção e de menos código.

Na maior parte do código real, encaminhar é a opção mais segura e simples.

#include <stdio.h>
#include <stdarg.h>

void say(const char *fmt, ...) {
    va_list args;
    va_start(args, fmt);
    vfprintf(stdout, fmt, args);
    va_end(args);
}

int main(void) {
    say("%s = %.1f\n", "pi", 3.14);
    return 0;
}

Incompatibilidade causa comportamento indefinido

Se a cadeia de formato promete um tipo que não corresponde ao argumento real, o comportamento é indefinido.

printf("%d", "text") pode causar uma falha. Mantenha sempre o formato e os argumentos sincronizados.

#include <stdio.h>

int main(void) {
    int n = 5;
    printf("%d\n", n);
    return 0;
}

Verificação rápida

Teste sua compreensão de funções de encapsulamento no estilo de printf.

Recapitulação

Você aprendeu a criar funções semelhantes a printf:

  • Receba uma cadeia de formato como parâmetro nomeado e, depois, ....
  • Analise você mesmo os especificadores % e leia os tipos correspondentes ou
  • encaminhe a va_list para vprintf / vsnprintf para obter uma formatação segura e correta.
  • Mantenha o formato e os tipos dos argumentos sincronizados para evitar comportamento indefinido.

Perguntas Frequentes

A aula “Escrevendo funções semelhantes a printf” é grátis?

Sim — o texto completo de “Escrevendo funções semelhantes a printf” é 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 “Escrevendo funções semelhantes a printf”?

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 2 de 4.

Quanto tempo leva a aula “Escrevendo funções semelhantes a printf”?

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

  1. As macros stdarg
  2. Escrevendo funções semelhantes a printf
  3. Questões de segurança de tipos
  4. Exemplos práticos
← Voltar para C Academy