Boomer C
Boomer C: A Legacy of Questionable C Practices
Disclaimer: Boomer C Knows No Age
Despite the name, Boomer C is not exclusively written by boomers. In fact, you don’t need to be old to write code that looks like it was faxed straight out of a 1987 UNIX lab. Whether you're a fresh-out-of-college engineer who picked up bad habits from legacy codebases, a seasoned developer who just refuses to abandon K&R function declarations, or an AI-generated C programmer making "bold" choices—Boomer C welcomes all (including myself).
And let’s be honest—there’s something strangely charming about it. The raw minimalism, the defiant disregard for modern conventions, the way it just works (until it doesn't). It's the kind of code that feels like it was written with a cigarette in one hand, a coffee-stained manual in the other, and absolutely zero concern for "best practices."
So while we poke fun at it, let’s also take a moment to appreciate the Boomer C spirit: a testament to C’s rugged, unkillable nature. It may be ugly, but by God, it works.
Introduction
In my experience working on a wide range of systems software—including device drivers, Linux, other operating systems, and high-performance computing (HPC) libraries—I've encountered a recurring pattern of C programming habits that feel like relics of an earlier era. These coding styles, often found in legacy codebases or written by seasoned engineers who have been using C since the 1980s, exhibit a mix of outdated conventions, compiler-era quirks, and practices that are either unnecessarily cryptic or outright hazardous. After seeing these patterns repeatedly, I started referring to it as Boomer C.
Boomer C is the name given to a collection of outdated, dangerous, or just plain ugly C programming habits that refuse to die. Rooted in the early days of C—when compilers were more permissive, documentation was sparse, and developers were more concerned with making things "just work" than writing maintainable code—Boomer C is a relic of an era where undefined behavior was just "how things were done." This style includes everything from missing {}
brackets in control structures to K&R-style function declarations, implicit types, and reckless macro abuse. While some of these patterns were once necessary due to compiler limitations, today they are mostly indicators of legacy codebases, old-school programmers who refuse to change, or outright dangerous programming habits that should be left in the past. Recognizing Boomer C is the first step toward writing safer, more modern, and maintainable C code.
Here is an incomplete taxonomy of some of the things I have come to know as “Boomer C“
Control Flow & Syntax Quirks
if, for, while without {} brackets
if (x > 0)
printf("Positive\n");
- One-line conditionals are a classic footgun.
Assignment inside conditions
if (x = 5) // Whoops, meant ==
printf("X is 5\n");
- Old-school trick for terseness but often leads to subtle bugs.
Using goto for control flow
if (condition)
goto label;
- Yes, goto has valid uses (notably, error handling), but most of the time it's just chaos.
Using switch without break (fall-through hell)
switch (x) {
case 1: printf("One\n");
case 2: printf("Two\n");
default: printf("Default\n");
}
- Fall-through should always be explicit!
Function & Typing Abominations
K&R-style function definitions
int add(a, b)
int a, b;
{
return a + b;
}
- This is pre-C89 syntax but still lurking in ancient codebases.
Anonymous function parameters
int foo(int, float);
- Old compilers tolerated it, but it's bad for readability.
Function arguments defaulting to int
func(a, b) { return a + b; }
- Allowed in prehistoric C, but should be extinct now.
Implicit return type (defaults to int)
main() {
printf("Hello, world!\n");
}
int main(void)
exists for a reason.
Declarations & Typing Nonsense
Mixing declarations and code (pre-C99 style)
int x = 5;
printf("%d", x); // ERROR in modern C (pre-C99 required declarations first)
int y = 10;
- Forces all declarations at the top of a block.
Implicit int type in declarations
static foo = 42;
- int is assumed, but this is no longer valid in C99+.
Declaring main() with a missing return type
main() {
printf("Hello\n");
}
- It should be int main(void), but legacy code is full of this.
Using register for variables (useless in modern compilers)
register int i = 0;
- Modern compilers ignore register hints anyway.
Memory & Pointers Madness
Assigning a string literal to char * (writable)
char *s = "Hello";
s[0] = 'h'; // SEGFAULT? Maybe.
- String literals are immutable in modern C.
Using void *
for generic data storage
void *data = (void *)42;
- Except for opaque handles, just use proper types.
Old-school alloca()
usage (stack allocation horror)
char *buf = alloca(1024);
- Easy way to blow the stack.
Preprocessor & Macro Crimes
Defining constants with #define instead of const
#define SIZE 100
const int SIZE = 100;
is better in most cases.
Multi-line macros without do { ... } while (0) safety
#define SQUARE(x) x * x
int area = SQUARE(5 + 2); // Surprise! area = 5 + 2 * 5 + 2
Should be #define SQUARE(x) ((x) * (x))
Using #define to fake functions
#define MIN(a, b) a < b ? a : b
- Needs parentheses:
#define MIN(a, b) ((a) < (b) ? (a) : (b))
Using #include inside a function
void foo() {
#include <stdio.h>
printf("Hello\n");
}
- What were they thinking?
Miscellaneous Boomer C Habits
Using gets()
(dangerous buffer overflows)
char buf[100];
gets(buf);
- Use fgets(buf, sizeof(buf), stdin) instead!
Using printf("%s", user_input)
(format string vulnerability)
printf(user_input);
- This allows arbitrary memory access if the user provides
%x %x %x
.
Using system("pause")
for debugging
system("pause"); // Windows-only, and a bad idea.
- Just use
getchar()
.
Returning garbage from main()
nt main() {
printf("Hello\n");
}
- Always
return 0;
at the end.
Relying on old-style headers (stdio.h vs. cstdio)
#include <iostream.h> // Wrong!
- C++-style headers like <iostream.h data-preserve-html-node="true"> have been dead since the '90s.
Using void main()
void main() {
printf("Hello\n");
}
main
must returnint
, period.