An earlier batch of bizarre C Hello World programs was meant as entertainment, and readers took it that way. Some examples were funny, some were impressive, and most were deliberately absurd. But there was a less amusing observation underneath the jokes: clear source code does not stay clear by accident. Every programmer has some capacity to turn a straightforward program into a tangle, even if it never reaches Hello World levels of weirdness.

The following exercise starts with a short prime-finding program and makes it progressively harder to read. None of the steps require exotic tricks. They are ordinary moves—loop rewriting, recursion, ternaries, repeated expressions, vague names—applied with enough persistence.

Start with a clean version:

void primes(int cap)
{
    int i, j, composite;

    for(i = 2; i < cap; ++i) {
        composite = 0;
        for(j = 2; j * j < i; ++j) {
            composite += !(i % j);
        }
        if(!composite){
            printf("%dt", i);
        }
    }
}

int main()
{
    primes(100);
}

Here is the first rewrite. The nested for loops become a single while loop over cap * cap, with i and j recomputed from a running counter. The two-dimensional traversal is flattened, and a chain of if / else if statements handles the cases:

void primes(int cap)
{
    int i, j, composite, t = 0;

    while(t < cap * cap) {
        i = t / cap;
        j = t++ % cap;
        if(i <= 1);
        else if(!j)
            composite = j;
        else if(j == i && !composite)
            printf("%dt",i);
        else if(j > 1 && j < i)
            composite += !(i % j);
    }
}

int main()
{
    primes(100);
}

Next, replace the while loop with recursion. Recursion can make code simpler in some situations; here it mainly adds parameters and inefficiency. The function now takes three arguments, and each branch calls itself with an updated counter and composite count:

void primes(int cap, int t, int composite)
{
    int i,j;
    i = t / cap;
    j = t % cap;
    if(i <= 1)
        primes(cap,t+1,composite);
    else if(!j)
        primes(cap,t+1,j);
    else if(j == i && !composite)
        (printf("%dt",i), primes(cap,t+1,composite));
    else if(j > 1 && j < i)
        primes(cap,t+1, composite + !(i % j));
    else if(t < cap * cap)
        primes(cap,t+1,composite);
}

int main()
{
    primes(100,0,0);
}

The next step is to obscure the control flow. One easy way is to replace the if / else if chain with conditional ? : expressions. The variable names also become less descriptive, which makes the reader work harder to recover the original idea:

void primes(int m, int t, int c)
{
    int i,j;
    i = t / m;
    j = t % m;
    (i <= 1) ? primes(m,t+1,c) : (!j) ? primes(m,t+1,j) : (j == i && !c) ?
    (printf("%dt",i), primes(m,t+1,c)) : (j > 1 && j < i) ?
    primes(m,t+1,c + !(i % j)) : (t < m * m) ? primes(m,t+1,c) : 0;
}

int main()
{
    primes(100,0,0);
}

Temporary variables usually hold the value of an expression that is used repeatedly. Removing them and repeating the expression inline makes the code longer and harder to scan:

void primes(int m, int t, int c)
{
  ((t / m) <= 1) ? primes(m,t+1,c) : !(t % m) ? primes(m,t+1, t % m) :
  ((t % m)==(t / m) && !c) ? (printf("%dt",(t / m)), primes(m,t+1,c)) :
  ((t % m)> 1 && (t % m) < (t / m)) ? primes(m,t+1,c + !((t / m) % (t % m))) :
  (t < m * m) ? primes(m,t+1,c) : 0;
}

int main()
{
    primes(100,0,0);
}

Identifiers can be made even less informative. Underscores are valid in C identifiers, so the variables m, t, and c can become __, ___, and ____; the function name can become _:

void _(int __, int ___, int ____)
{
    ((___ / __) <= 1) ? _(__,___+1,____) : !(___ % __) ? _(__,___+1,___ % __) :
    ((___ % __)==(___ / __) && !____) ? (printf("%dt",(___ / __)),
    _(__,___+1,____)) : ((___ % __) > 1 && (___ % __) < (___ / __)) ?
    _(__,___+1,____ + !((___ / __) % (___ % __))) : (___ < __ * __) ?
    _(__,___+1,____) : 0;
}

int main()
{
    _(100,0,0);
}

The last step removes remaining constants from the main body. One option is a macro; another is an extra function parameter. Adding another parameter keeps the call signature awkward and pushes the constant out of sight:

void _(int __, int ___, int ____, int _____)
{
    ((___ / __) <= _____) ? _(__,___+_____,____,_____) : !(___ % __) ? _(__,___+_____,___ % __, _____) :
    ((___ % __)==(___ / __) && !____) ? (printf("%dt",(___ / __)),
    _(__,___+_____,____,_____)) : ((___ % __) > _____ && (___ % __) < (___ / __)) ?
    _(__,___+_____,____,_____ + !((___ / __) % (___ % __))) : (___ < __ * __) ?
    _(__,___+_____,____,_____) : 0;
}

int main() {
    _(100,0,0,1);
}

At this point the program is thoroughly unpleasant to read, but it still follows the same basic sequence of calculations. The transformation did not require a compiler bug, an obscure language feature, or a malicious tool. It came from a series of small, ordinary decisions that each made the code a little less clear.

Every programmer has the potential to make source code complicated. The degree varies, but the potential is there.