Worst abuse of the C preprocessor (IOCCC winner, 1986)-Jim Hague

Christopher Caswell
6 min readMar 9, 2021

A blog for personal edification with the Holberton Curriculum.

Contestants compete to be the best-worst

Jim Hague wrote a program in 1986 to compete in the IOCCC contest.

The goals of the IOCCC are as follows(copy pasta’d from their home page):

* To write the most Obscure/Obfuscated C program under the rules below.
* To show the importance of programming style, in an ironic way.
* To stress C compilers with unusual code.
* To illustrate some of the subtleties of the C language.
* To provide a safe forum for poor C code. :-)
Jim Hague’s piece of art
Admit it, this is how you feel after reading that

The program prints whatever you place into it in Morse Code.

The program performs this action by creating a series of macros that are similar visually but differ in form and function by margins of degree.

A macro is essentially a variable block that will be replaced by a piece of code or a hotdog, whichever you choose. In this program , we #define __DAH such that every time you see it, it prints the characters ++.

Mr. Hague’s code is hilarious and messy for the sheer volume of macros implemented. But it runs. And for that, I call it art. I aspire to be so capable of malarky. There’s so many more examples, and they’re so beautiful.

  • _DIT will become string
  • DAH_ will become c
  • _DAH_[] will become morse
  • _DIT_ will become morsecpy
  • DIT_DAH will create the memory necessary to function
Page 171.A in your textbooks

When the code goes to compilation, the GCC compiler will remove all comments (including the header files) and expand the macros. We use the flag -E to tell gcc to kick out an *.i file.

Preprocessing means -only- the steps listed above and that we are ceasing action there.

The breakdown of code

If you look at the above code and back to this code (now back to that code, now back to me, I’m on a horse) you’ll find some translations of note.

There is, in fact, a main function to be called. The importance of libraries cannot be understated here.

Getting started! In order to understand the logic of the code, replace every macro by its value then lose the unnecessary white space.

In all sections of the code, there are variables passed(like _DAH_[], which is a character array). Give these variables simpler, more complete names and change the names of the functions to standard functions. The code starts to look less like bridge ramblings and more like a precise concept. There is a lot of plug and play in this code.

__DIT() did the same as the library function putchar(), which prints a character to the standard output(read as: your compooting screen). Given my parameters, I used _putchar, following my own library functions. It was a while before I realized I should just be using the standard library. #regrets

The function needs to be passed a parameter of type int because it is compared to an int. So pass it the parameter c.

The function is recursive until it reaches a base case. The base case is if c is under or equal to 3. Then it will print a terminating null character (aka the 00, Null Bite, ‘\0’, the only slice of pizza), which marks the end of strings in C.

It was wiser to correct the _putchar() function to the one from the standard library. Add a return type of int and a return statement to the system call “write” given by the original program. The function will print the char c.

Now the process of the code:

Outside Loop

  1. Dynamically allocate 81 bytes in memory for the input string, and settle next to the following character inside the string
  2. Loop until the end of the input string (aka the 00, Null Bite, ‘\0’, the last of my pepperoni David).
  3. Print a new line

This loop executes the code and then prints a new line, ready to take the next string from the standard input.

Middle Loop

  1. Set the current character c to the current character in the input string
  2. Continue until the string c reaches the ‘\0’ character
  3. A ternary operator calls to putchar, which works like an if/else conditional statement. (If the current character in morsecpy is different from ‘\0’, print the value given by the call to translate() with next as its parameter. If not, print a ‘?’). Then we print a space. Then we move on to the next character in c.

This loop will print the Morse symbols. This will loop entirely for every iteration of the previous loop.

Inside Loop

  1. We set the current character next to 2 and set the morsecpy character to the character in morse
  2. Until the end of morsecpy and while morsecpy is different from the result of another ternary operator, the loop runs. (Is *c ≥ lowercase a? If yes then the result is *c & 223. If no, it’s *c. The second part of the ending condition questions *morsecpy’s difference from *c. The loop continues as long as the *c variable doesn’t match the characters in morse[])

3. Increase by one and move to the next character in morsecpy

This loop will run entirely for every iteration of the previous loop.

Honestly, this hurt my brain trying to figure it all out. Some of the code has been a little messy, even after cleaning. And I’m sure I can be reached for further discussion. The task was so in-depth that I had little time for humor. Thank you for indulging me.
I guess the note to take away here is if you spend your whole life staring at the sun, you’re not very bright.

--

--

Christopher Caswell

software developer, agile enthusiast, digital entomologist