The C preprocessor can make your code unreadable(IOCCC winner, 1986)

Morse code is an old method to express words, sentences or letters by using only three symbols. These symbols are short signals, long signals and pauses.
For example you could use sound, light or electronic signals. Or when you write in morse code you could use the characters: “.” “-” “ ”. A suitable scenario for morse code is when you try to use short words that stand for a special meaning. A well known example is “SOS” which gets translated to “…− − − …”. The graphic above illustrates the translation of each alphabetic letter in morse code.
C Program by Jim Hague (1986)
In the following I am going to explain how Jim Hague (born in the UK) programmed a C program that translates ASCII code which is inserted in standard input to Morse code.
With his program Jim Hague won the IOCCC contest in 1986. I was a contest about who can create the most confusing and unorganized code for something basic. It mainly makes use of the precompiler, which is the first part of the gcc compiler.
This is the code of his c program. In our case it is called “hague.c”
#define DIT (
#define DAH )
#define __DAH ++
#define DITDAH *
#define DAHDIT for
#define DIT_DAH malloc
#define DAH_DIT gets
#define _DAHDIT char
_DAHDIT \
_DAH_[]="ETIANMSURWDKGOHVFaLaPJBXCYZQb54a3d2f16g7c8a90l?e'b.s;i,d:"
;main DIT DAH{_DAHDIT
DITDAH _DIT,DITDAH DAH_,DITDAH DIT_,
DITDAH _DIT_,DITDAH DIT_DAH DIT
DAH,DITDAH DAH_DIT DIT DAH;DAHDIT
DIT _DIT=DIT_DAH DIT 81 DAH,DIT_=_DIT
__DAH;_DIT==DAH_DIT DIT _DIT DAH;__DIT
DIT'\n'DAH DAH DAHDIT DIT DAH_=_DIT;DITDAH
DAH_;__DIT DIT DITDAH
_DIT_?_DAH DIT DITDAH DIT_ DAH:'?'DAH,__DIT
DIT' 'DAH,DAH_ __DAH DAH DAHDIT DIT
DITDAH DIT_=2,_DIT_=_DAH_; DITDAH _DIT_&&DIT
DITDAH _DIT_!=DIT DITDAH DAH_>='a'? DITDAH
DAH_&223:DITDAH DAH_ DAH DAH; DIT
DITDAH DIT_ DAH __DAH,_DIT_ __DAH DAH
DITDAH DIT_+= DIT DITDAH _DIT_>='a'? DITDAH _DIT_-'a':0
DAH;}_DAH DIT DIT_ DAH{ __DIT DIT
DIT_>3?_DAH DIT DIT_>>1 DAH:'\0'DAH;return
DIT_&1?'-':'.';}__DIT DIT DIT_ DAH _DAHDIT
DIT_;{DIT void DAH write DIT 1,&DIT_,1 DAH;}
Unedited the code does not look easy to follow. But in the following I am going to simplify it line by line so any reader of my blog should be able to easily follow up the used steps to translate into morse code.
Compilation and Use
If you try to compile this program with the “gcc compiler” you likely will get some warning messages. But either way you can happily ignore these messages because the program is going to compile the way it should.
nick $ gcc hague.c -o h
hague.c: In function ‘main’:
hague.c:6:17: warning: conflicting types for built-in function ‘malloc’ [enabled by default]
#define DIT_DAH malloc
^
hague.c:12:37: note: in expansion of macro ‘DIT_DAH’
DITDAH _DIT_,DITDAH DIT_DAH DIT
^
/usr/bin/ld: /tmp/ccTrArpL.o: in function `main’:
hague.c:(.text+0x148): warning: the `gets’ function is dangerous and should not be used.
Here I am going to show an example of its usage. In the following I am going to translate “Hello, world”. After you run the program you get promped to type in your desired sentence and submit it by pressing “Enter”
nick $ ./h
hello world
…. . .-.. .-.. — — ? . — — — .-. .-.. -..
First lines
So now how does the code work. Let me start by explaining the first two lines.
#define DIT (
#define DAH )
So here we are creating the two macros “DIT” and “DAH”. This means that whenever the precompiler will encounter DIT it will be replaced by “(” and “DAH” will be replaced by “)”. “#define” is a precompiler identifier, This means that before compiling the code to assembler code all precompiler identifiers are going to be replaced.
Because as we know the “C” compilation consists of the 4 steps precompiling, compiling, assembling, linking.
Precompiler function
If you are new to the compilation process you may ask what exactly the tasks of the precompiler are. These are crucial to understand to understand the concept of using the precompiler macros and directives so I am going to give you a short overview.
First the precompiler will remove all comments from your code. These are detectable by a starting “/*” and an following “*/”. If the precompiler detects the token “//” it will remove it and the rest of the words following in this line.
After that the precompiler will include the whole code of your included header files. “<stdlib.h>” is one.
Then it will look for directives and macros and expand them. Macros are defined by the string “#define”.
Line 3 - 6
#define __DAH ++
#define DITDAH *
#define DAHDIT for
#define DIT_DAH malloc
#define DAH_DIT gets
#define _DAHDIT char
Here we define the macro __DAH and set its value to “++”. After that we define “DITDAH” and set its value to “*”. We set “DAHDIT” to “for” and “DIT_DAH” to “malloc”. And finally we set the value “gets” to the macro “DAH_DIT” and the value “char” to the value “_DAHDIT”. Now when you are going to precompile you program whenever the precompiler is going to encounter a String which is identical to a defined Macro it will be replaced by its declared value.
Now all macros of the function are defined and the actual Code begins.
Precompiled code
I am going to show you the precompiled code so we can see the code after it translates its macros with its values.
I can do this easily with the command “gcc -E hague.c -o <filename>”
# 1 “hague.c”
# 1 “<built-in>”
# 1 “<command-line>”
# 1 “/usr/include/stdc-predef.h” 1 3 4
# 1 “<command-line>” 2
# 1 “hague.c”
# 9 “hague.c”
char _DAH_[]=”ETIANMSURWDKGOHVFaLaPJBXCYZQb54a3d2f16g7c8a90l?e’b.s;i,d:”
;main ( ){char
* _DIT,* DAH_,* DIT_,
* _DIT_,* malloc (
),* gets ( );for
( _DIT=malloc ( 81 ),DIT_=_DIT
++;_DIT==gets ( _DIT );__DIT
(‘\n’) ) for ( DAH_=_DIT;*
DAH_;__DIT ( *
_DIT_?_DAH ( * DIT_ ):’?’),__DIT
(‘ ‘),DAH_ ++ ) for (
* DIT_=2,_DIT_=_DAH_; * _DIT_&&(
* _DIT_!=( * DAH_>=’a’? *
DAH_&223:* DAH_ ) ); (
* DIT_ ) ++,_DIT_ ++ )
* DIT_+= ( * _DIT_>=’a’? * _DIT_-’a’:0
);}_DAH ( DIT_ ){ __DIT (
DIT_>3?_DAH ( DIT_>>1 ):’\0');return
DIT_&1?’-’:’.’;}__DIT ( DIT_ ) char
DIT_;{( void ) write ( 1,&DIT_,1 );}
Now I will manually bring the code in a more readable position by setting the white-spaces and newlines in an accurate position.
# 1 “hague.c”
# 1 “<built-in>”
# 1 “<command-line>”
# 1 “/usr/include/stdc-predef.h” 1 3 4
# 1 “<command-line>” 2
# 1 “hague.c”
# 9 “hague.c”char \ _DAH_[]=”ETIANMSURWDKGOHVFaLaPJBXCYZQb54a3d2f16g7c8a90l?e’b.s\
;i,d:”;
main ( )
{
char * _DIT,* DAH_,* DIT_, * _DIT_,* malloc (),* gets ( );
for ( _DIT=malloc ( 81 ),DIT_=_DIT++;_DIT==gets ( _DIT );__DIT(‘\n’) )
for ( DAH_=_DIT;* DAH_;__DIT ( *_DIT_?_DAH ( * DIT_ ):’?’),__DIT(‘ ‘),DAH\
_ ++ )
for (* DIT_=2,_DIT_=_DAH_; * _DIT_&&(* _DIT_!=( * DAH_>=’a’? *DAH_&223:* DAH_ ) ); (* DIT_ ) ++,_DIT_ ++ )* DIT_+= ( * _DIT_>=’a’\
? * _DIT_-’a’:0);
}
_DAH ( DIT_ ){ __DIT (DIT_>3?_DAH ( DIT_>>1 ):’\0');
return DIT_&1?’-’:’.’;
}
__DIT ( DIT_ ) char DIT_;
{
( void ) write ( 1,&DIT_,1 );
}
If you now want so simplify the code even more you could change the name of the variables _DAH, DIT_, _DIT_ and DAH_ with the following linux command:
sed -i ‘s/<_DIT_>/<desired name>/g’ <filename>
Line 9–23
Now we finally have a better readable code. But still it is not readable enough as single lines are exceeding 40 characters.
Either way the way the morse code translation is working, can be understood from the code.
How did he win the contest
So if we refer back to the original file how did Hague won the contest and made the most unreadable code of the contest.
On the one hand he uses a lot of macros to change the meaning of basic words. And on the other hand he creates very long “for loops” and sets blank spaces and newlines on completely inadequate places.