Problemer med typesikkerhed
Risici ved variadiske funktioner
Problemer med typesikkerhed er en gratis C Academy-lektion på CoddyKit. Dette er lektion 3 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i C Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. C Academy-kurset indeholder 4 lektioner i alt.
Variadiske argumenter omgår typekontrol
Normale C-funktioner kontrollerer, at argumenterne stemmer overens med parametertyperne. Variadiske argumenter springer helt denne kontrol over.
Compileren kan ikke kontrollere, hvad du sender efter ..., hvilket gør fejl nemme at begå og farlige.
#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;
}Forkert type i va_arg
Hvis du læser et argument med den forkerte type, er resultatet udefineret opførsel.
Hvis du sender en int, men læser den som en double, fortolkes irrelevante bytes på ny, hvilket giver skrald eller et nedbrud.
#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;
}Uoverensstemmelser i formatstrenge
I printf-funktioner er en forkert specifikation en klassisk fejl. printf("%d", 3.14) læser en double, som om den var en int.
Moderne compilere advarer om uoverensstemmelser i bogstavelige formater, men kan ikke opdage formatstrenge, der bygges under kørsel.
#include <stdio.h>
int main(void) {
double pi = 3.14;
printf("%f\n", pi);
return 0;
}Overraskelser ved heltals-promovering
Små typer promoveres til int i den variadiske del. Så selv hvis du sender en char, skal du læse den tilbage som en int.
Det er udefineret at læse den som char med va_arg(a, char).
#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 bliver til double
Et float-argument promoveres altid til double i variadiske argumenter. Du skal læse det som double, aldrig som float.
Dette er en af de mest almindelige variadiske fejl.
#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;
}Læsning af for mange argumenter
Hvis din kode kalder va_arg flere gange, end kalderen har sendt argumenter, læser du skrald fra stakken.
Derfor er et nøjagtigt antal eller en sentinel afgørende.
#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;
}NULL-pointer-sentinler kræver omtanke
Det er risikabelt at bruge NULL som sentinel: På nogle platforme er NULL en 0 af typen int, som har en anden størrelse end en pointer.
Cast den eksplicit, f.eks. som (char *)NULL, for at sikre, at den korrekte type sendes.
#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;
}Formatattributter til compileren
GCC og Clang tilbyder __attribute__((format(printf, 1, 2))), så du kan fortælle compileren, at din funktion bruger formatering i printf-stil.
Derefter kontrollerer den dine formatstrenge på kompileringstidspunktet og opdager mange fejl.
#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;
}Foretræk sikrere alternativer
Da variadiske argumenter er fejlbehæftede, bør du så vidt muligt foretrække typesikre design: Send et eksplicit array, en struct eller faste parametre.
Gem variadiske argumenter til reelle printf-lignende behov.
#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;
}Dokumentér kontrakten
Da compileren ikke kan håndhæve typerne for variadiske argumenter, er tydelig dokumentation dit sikkerhedsnet.
Angiv præcis, hvilke typer og hvor mange argumenter kalderen skal sende, samt hvordan listen afsluttes.
#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;
}Grundig test
Da fejl kan skjule sig ubemærket, skal du teste variadiske funktioner med mange antal argumenter og typer.
Grænsetilfælde som nul argumenter eller det maksimale antal afslører ofte fejl.
#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;
}Hurtigt tjek
Test din forståelse af risiciene ved variadiske typer.
Opsummering
Du har lært om farerne ved variadiske funktioner:
- Compileren typekontrollerer ikke variadiske argumenter.
- Forkerte typer, forkerte antal og ugyldige sentinler medfører udefineret opførsel.
- Husk promoveringerne: små heltal til
int,floattildouble. - Brug compilerens formatattributter, dokumentér kontrakten, og foretræk typesikre alternativer, når du kan.
Lær C med en AI-underviser — gratis
Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.
- Kurser
- 39
- Lektioner
- 144
Ofte stillede spørgsmål
Er lektionen “Problemer med typesikkerhed” gratis?
Ja — hele teksten til “Problemer med typesikkerhed” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af C Academy-kurset, skal du opgradere til CoddyKit PRO. C Academy-kurset indeholder 4 lektioner i alt.
Hvad lærer jeg i “Problemer med typesikkerhed”?
Risici ved variadiske funktioner Du øver dig i C Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.
Skal jeg have erfaring for at begynde på C Academy?
Der kræves ingen tidligere erfaring. C Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 3 af 4.
Hvor lang tid tager lektionen “Problemer med typesikkerhed”?
De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.
Kan jeg skrive og køre kode i denne C Academy-lektion?
Ja. Alle C Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.
Alle lektioner i dette kursus
- stdarg-makroerne
- Skriv printf-lignende funktioner
- Problemer med typesikkerhed
- Praktiske eksempler