:date: 2026-07-26 09:35
Like many C programmers, I have an immense respect for the creators of C, Dennis Ritchie and Brian Kernighan (aka K&R). As I worked on my SnowC project, the initial test cases I focused on were code examples from their foundational book "The C Programming Language". Along the way I discovered something fascinating — many times I was surprised to find that my correctly generated SnowC was nearly identical to the original C code.
Consider this example on page 58 (of this online version, p63 of my 1st ed paperback, p66 of my 2nd ed paperback).
for (i = 0; i < n; i++)
for (j = 0; j < m; j++)
if (a[i] == b[j])
goto found;
/* didn't find any common element */
found:
This is C code where K&R explain when using goto is cool with them.
Here is the corresponding SnowC code.
$ ./c2snowc /tmp/KR058.c
for (i = 0; i < n; i++)
for (j = 0; j < m; j++)
if (a[i] == b[j])
goto found
/* didn't find any common element */
found:
You can see why I was sometimes confused by my conversion program
seemingly not doing anything. (Thank goodness for vimdiff!)
In fact, this original K&R code, which is literally a foundational illustrative textbook example of the C language, is also perfectly valid SnowC! Look what happens when I convert this C as if it were SnowC.
$ ./snowc2c /tmp/KR058.c
for (i = 0; i < n; i++) {
for (j = 0; j < m; j++) {
if (a[i] == b[j]) {
goto found;
}
}
}
/* didn't find any common element */
found:
Obviously nobody writes code like that, right? Obvsiously everybody follows K&R, right? Wrong!
Let's explore what other people think about control keywords with single statements (what I call "singletons"). Singletons are very clever and the extremely clever K&R love them! But the rest of the world has to work with much less clever programmers, and they have become sensibly wary.
The Linux C Programming Style Guide is a fun read and you can learn what Linus himself (presumably) thinks about things. The kernel team shares my immense respect for the creators of C.
Heretic people all over the world have claimed that this inconsistency is ... well ... inconsistent, but all right-thinking people know that (a) K&R are right and (b) K&R are right. ...even the makers of GNU indent recognize the authority of K&R (the GNU people aren’t evil, they are just severely misguided...)
Just after making an imperial pronouncement on how braces should be
styled in else and do situations — or even possibly omitted, oh
my! — Linus offers up the dispute ending three character
justification: "Rationale: K&R."
However, just a bit later he backs down a bit disallowing else
singletons paired with multi-statement if blocks (and vice versa).
However, this is exactly what K&R do right out of the gate with their
word count program on
page
22!
Linus then carves into stone this very reasonable commandment...
Also, use braces when a loop contains more than a single simple statement:
while (condition) {
if (test)
do_something();
}
Hang on, Linus, didn't we just see that kind of thing in my first example? For better or worse, this Linux style is definitely not orthodox K&R!
What about Google's style guide? (Shamefully a web page on their biggest competitor's website. Yuck.)
Google tepidly condones the mildest of singletons. For example.
// OK - braces are optional in this case.
if (x == k) return Foo();
// OK - condition fits on one line, body fits on another.
if (x == k)
Bar(arg1, arg2, arg3);
However, they disallow any singletons having anything to do with
else or do. (An assumption that would have sliced a week off of
SnowC's development!)
In the section Looping And Branching Statements it says,
Use this style only when the statement is brief, and consider that loops and branching statements with complex conditions or controlled statements may be more readable with curly braces. Some projects require curly braces always.
What would K&R think of "curly braces always"? Since I was using their
code examples to test SnowC conversions I have a pretty good
collection of the their gospel code. And because c2snowc internally
starts with a rough labeling of the important kinds of characters in C
code there is a diagnostic feature where I can print that mapping out.
And becasue singletons are so problematic, they get their own
extensive logic and must be properly identified and marked. Here is a
structural look at all the lines in K&R which involve multiline
singletons (marked with 1). You can cross reference yourself with
the
online
version of the book.
$ for F in testing/challenge/KR*c ; do echo $(basename $F); ./c2snowc -m $F | sed -n 2~2p | grep 1 ; done
KR022-wc.c
........11_(C_CC_'''')+
........11_(C_CC_'''_CC_C_CC_''''_CC_C_C_'''')+
........1111_CC_(CCCCC_CC_CCC),{+
KR030-fn.c
....11111_(CCCC_C_CCCCCCCCCCCCC_CCCCCCCCC_C_C)+
....11_(CCC_C_C),//////////////////////+
....111_(CCCC_C_C_CCCCC_CC_CCCCCCCCCCCCCCCCCC_CC_CCC''''C_CCC)+
....11111_(CCCCCC_C_CCCCCCCC_CC_'''')+
KR051-badelse.c
11_(C_C_C)+
....111_(C_C_CC_C_C_CC_CCC)+
1111,///////////+
KR052-if.c
........11_(C_C_CCCCCC)+
........1111_11_(C_C_CCCCCC)+
........1111,/////////////////+
KR053-switch.c
....111_(C_C_CC_C_C_CCC_CCC)+
....111_(C_C_CC_C_C_CCC_CCC)+
KR055-for.c
111_(CCC_C_CCCC_CCC_C_CC_CCC_CC_C)+
....111_(C_C_CCCC_C_C_CC_CCC)+
KR056-dowhile.c
....11_(CCCCC_C_CC_C_C),/////////////////+
....}.11111_(CC_CC_CCC_C_C);,///////////////+
....11_(CCCC_C_C)+
KR074-fn.c
....11_(CCCC_CC_CCCCC),//////////////////////////////////+
....111_(C_C_CCCC_C_CC_C_CC_CCCCCC_CCC),///////////////+
........11_(CCCC_C_CCCCCCC)+
KR092-defbraces.c
....111_(C_C_CC_C_C_CCCCCC_CCC)+
....111_(C_C_CC_CCCCCCC_C_CCCCCCCCCCCCCCCC_CCC)+
KR096-args.c
....11111_(CCCCCC_C_C)+
KR097-find.c
....11111_(CCCCCC_C_C_CC_CCCCCCCCCCCC_CC_''')+
........11111_(C_C_CCCCCCCCCC)+
....11_(CCCC_CC_C)+
....1111+
................11_(CCCCCC)+
KR132-cat.c
....11_(CCCC_CC_C),//////////////////////////////////+
....1111+
........11111(CCCCCC_C_C)+
....11111_(CC_C_CCCCCCCCCC_CC_CCC)+
KR146-dirwalk.c
....11_(CCCC_CC_C),,////////////////////////////////+
....1111+
........11111_(CCCCCC_C_C)+
....11_(CCCCCCCCCCCCCC_C_CCCCCCC_CC_CCCCCCC)+
........11_(CCCCCCCCCCCCCCCC_$$$C_CC_C+
........11_(CCCCCCCCCCCCCCCCCCCCCCCCCCCCCC_C_CCCCCCCCCCCC)+
....11_(CCC_C_CCCCCCCCCCCCC_CCCCCCCCC_CCC_CC_CC+
........11_(CCCCCCCCCCCC_CC_C),/////////////////////+
These guys were unambiguously huge fans of not using curly braces. They avoided doing so in pretty much every case where it was legal. If you flip through the book, you will never see horrendous piles of closing brace madness. Horrendous piles of closing brace madness is a real thing and it is exactly what inspired me to write SnowC. I can imagine that if I went back in time and proposed SnowC to K&R as they developed C, they wouldn't see what the big deal was. But it turns out that in complex code, it is a big deal. Python shows us that I'm not the first to notice this and that there is a better way. I believe it is the way that K&R were imagining all along.