C Academy · leksjon

Skrive printf-lignende funksjoner

Variable argumenter

Leksjon 2 av 413 trinn

Skrive printf-lignende funksjoner er en gratis leksjon i C Academy på CoddyKit. Dette er leksjon 2 av 4. Du kan lese hele leksjonen gratis nedenfor – og deretter øve praktisk i nettleseren med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i C Academy, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i C Academy inneholder totalt 4 leksjoner.

Funksjoner som tar en formatstreng

Den kraftigste bruken av variadiske argumenter er å bygge funksjoner i printf-stil som tolker en formatstreng.

Formatet forteller funksjonen hvor mange argumenter som følger, og hvilken type hvert av dem har.

#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;
}

Gå gjennom formatstrengen

Les formatet tegn for tegn. Når De ser et %, er det neste tegnet en konverteringsspesifikator som forteller hvilken type som skal leses.

Alt annet skrives ut bokstavelig.

#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;
}

Lese riktig type

Når spesifikatoren er %d, leser De en int. For %s leser De en char *. Formatet må stemme nøyaktig med de faktiske argumentene.

#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;
}

Håndtere flere spesifikatorer

Utvid skanningen slik at den håndterer flere konverteringer. Legg til tilfeller for %d, %s og %c, og les riktig type hver gang.

#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;
}

Escape prosenttegnet

Virkelige formatfunksjoner behandler %% som et bokstavelig prosenttegn. Legg til et tilfelle slik at brukerne kan skrive ut et faktisk %.

#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;
}

Videreformidle til vprintf

Ofte ønsker De ikke å implementere formateringen på nytt. Standardbiblioteket tilbyr vprintf, som tar en va_list direkte.

Wrapperen Deres sender ganske enkelt argumentene videre.

#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;
}

Legge til et prefiks

vprintf-metoden gjør det enkelt å legge til funksjonalitet rundt standardformateringen, for eksempel å skrive ut en etikett før hver melding.

#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;
}

Skrive til en buffer med vsnprintf

Hvis De vil formatere til en streng i stedet for å skrive den ut, bruker De vsnprintf(buf, size, fmt, args).

Den er begrenset av size, noe som hindrer overflyt, og avslutter alltid strengen med null-tegnet.

#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;
}

Returnere en lengde

vsnprintf returnerer antallet tegn som ville ha blitt skrevet. De kan bruke dette til å oppdage avkorting eller til å beregne riktig bufferstørrelse.

#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;
}

Velge fremgangsmåte

Det finnes to strategier: analyser formatet selv for full kontroll, eller send det videre til vprintf/vsnprintf for korrekthet og mindre kode.

For det meste av kode i praksis er videreformidling det tryggeste og enkleste valget.

#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;
}

Uoverensstemmelser gir udefinert oppførsel

Hvis formatstrengen angir en type som ikke stemmer med det faktiske argumentet, er oppførselen udefinert.

printf("%d", "text") kan krasje. Sørg alltid for at formatet og argumentene er synkronisert.

#include <stdio.h>

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

Rask kontroll

Test forståelsen Deres av wrappere i printf-stil.

Oppsummering

De har lært å bygge printf-lignende funksjoner:

  • Ta en formatstreng som navngitt parameter, etterfulgt av ....
  • Analyser enten %-spesifikatorene selv og les samsvarende typer, eller
  • videreformidle va_list til vprintf / vsnprintf for trygg og korrekt formatering.
  • Sørg for at formatet og argumenttypene stemmer overens, slik at De unngår udefinert oppførsel.
Gratis å komme i gang

Lær deg C med en AI-veileder – gratis

Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.

Kurs
39
Leksjoner
144

Ofte stilte spørsmål

Er leksjonen «Skrive printf-lignende funksjoner» gratis?

Ja – hele teksten i «Skrive printf-lignende funksjoner» er gratis å lese her på nettet. For å øve interaktivt med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt, og for å låse opp resten av C Academy-kurset, kan du oppgradere til CoddyKit PRO. Kurset i C Academy inneholder totalt 4 leksjoner.

Hva lærer jeg i «Skrive printf-lignende funksjoner»?

Variable argumenter Du øver på C Academy med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.

Trenger jeg erfaring for å begynne med C Academy?

Ingen tidligere erfaring er nødvendig. C Academy på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 2 av 4.

Hvor lang tid tar leksjonen «Skrive printf-lignende funksjoner»?

De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.

Kan jeg skrive og kjøre kode i denne C Academy-leksjonen?

Ja. Alle C Academy-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.

Alle leksjonene i dette kurset

  1. stdarg-makroene
  2. Skrive printf-lignende funksjoner
  3. Utfordringer med typesikkerhet
  4. Praktiske eksempler
← Tilbake til C Academy