You can simplify the args to printf by passing the string literals as the format string, rather than using a %s
to print them. This takes advantage of the fact that you know there are no %
characters in "fizz"
or "buzz"
. It's guaranteed to be safe to pass unused args to printf.
To make the source readable, pull the logic to select a format string out of the printf()
itself, and store it in a local variable.
#include <stdio.h>
int main(void)
{
int n=30;
for (int i = 1; i<=n; i++) {
int fizzy = (i % 3 == 0);
int buzzy = (i % 5 == 0);
const char *fmt = (fizzy && buzzy) ? "fizzbuzz\n" :
fizzy ? "fizz\n" :
buzzy ? "buzz\n" :
"%d\n";
printf(fmt, i);
}
}
It can be good style, and possibly make better asm, to conditionally determine the args you're going to pass and then make one call, instead of writing out the same function call with different args. This can be good if most of the args you're going to pass are the same in different branches, which is not the case here.
Normally it's better to just use puts
(implicit \n
appended) or fputs
to print constant strings that don't need formatting. Compilers know this, and even optimize printf("Hello World!\n");
or printf("%s\n", "Hello World!")
to puts("Hello World!");
in trivial cases. This trick means that even the fixed-string prints still make a call to the more expensive printf
. (Besides readability, this is one of the concrete reasons why it's not a great choice in this particular instance.)
gcc and clang compile this into asm that works the way the source does: printf
always gets two args (in the rdi
and rsi
registers), but sometimes the format string doesn't use the 2nd arg. Change -O3
to -Os
to make gcc use div
instead of a multiplicative inverse.
They don't unroll the loop to match the modulo pattern, or strength-reduce the modulos to down-counters, or anything clever like you'd do in a hand-written asm FizzBuzz.
For a devious way to write a compact FizzBuzz, see CodeGolf.SE, where a %s%s%.d
format string conditionally gets empty strings. The %.d
is specifies a precision of 0. Non-zero integers print normally, but 0
prints as the empty string.