Type Safety Concerns
Risks of variadics.
Type Safety Concerns is a free C Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the C Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Variadics bypass type checking
Normal C functions check that arguments match parameter types. Variadic arguments skip this check entirely.
The compiler cannot verify what you pass after the ..., which makes mistakes easy and dangerous.
#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;
}Wrong type in va_arg
If you read an argument with the wrong type, the result is undefined behavior.
Passing an int but reading it as a double reinterprets unrelated bytes and produces garbage or a crash.
#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;
}Format string mismatches
In printf-style functions, a wrong specifier is a classic bug. printf("%d", 3.14) reads a double as if it were an int.
Modern compilers warn about literal mismatches, but cannot catch runtime-built format strings.
#include <stdio.h>
int main(void) {
double pi = 3.14;
printf("%f\n", pi);
return 0;
}Integer promotion surprises
Small types are promoted to int in the variadic part. So even if you pass a char, you must read it back as an int.
Reading it as char with va_arg(a, char) is undefined.
#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 becomes double
A float argument is always promoted to double in variadics. You must read it as double, never float.
This is one of the most common variadic errors.
#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;
}Reading too many arguments
If your code calls va_arg more times than the caller supplied arguments, you read garbage off the stack.
This is why an accurate count or sentinel is essential.
#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 sentinels need care
Using NULL as a sentinel is risky: on some platforms NULL is 0 as an int, which differs in size from a pointer.
Cast it explicitly, like (char *)NULL, to ensure the right type is pushed.
#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;
}Compiler format attributes
GCC and Clang offer __attribute__((format(printf, 1, 2))) to tell the compiler your function uses printf-style formatting.
It then checks your format strings at compile time, catching many bugs.
#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;
}Prefer safer alternatives
Because variadics are error-prone, prefer type-safe designs when possible: pass an explicit array, a struct, or fixed parameters.
Reserve variadics for genuine printf-like needs.
#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;
}Document the contract
Since the compiler cannot enforce variadic types, clear documentation is your safety net.
State exactly which types and how many arguments the caller must provide, and how the list ends.
#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;
}Testing thoroughly
Because bugs hide silently, test variadic functions with many argument counts and types.
Boundary cases such as zero arguments or the maximum count often reveal mistakes.
#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;
}Quick Check
Test your understanding of variadic type risks.
Recap
You learned the dangers of variadic functions:
- The compiler does not type-check variadic arguments.
- Wrong types, wrong counts, and bad sentinels cause undefined behavior.
- Remember promotions: small ints to
int,floattodouble. - Use compiler format attributes, document the contract, and prefer type-safe alternatives when you can.
Frequently asked questions
Is the “Type Safety Concerns” lesson free?
Yes — the full text of “Type Safety Concerns” is free to read here on the web, and the C Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the C Academy course, upgrade to CoddyKit PRO.
What will I learn in “Type Safety Concerns”?
Risks of variadics. You practise C Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start C Academy?
No prior experience is required. C Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Type Safety Concerns” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this C Academy lesson?
Yes. Every C Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- The stdarg Macros
- Writing printf-like Functions
- Type Safety Concerns
- Practical Examples