The worst abuse of the C preprocessor (Jim Hague 1986)

Hadir Jenni
5 min readOct 19, 2020

what is IOCCC?

The International Obfuscated C Code Contest (abbreviated IOCCC) is a computer programming contest for the most creatively obfuscated C code ,

simply The IOCCC:

To write the most Obscure/Obfuscated C program within the rules.

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. :-)

What is the goal of IOCCC?

Obfuscate: tr.v. -cated, -cating, -cates.

1- To render obscure, to darken.

2- To confuse: his emotions obfuscated his judgment.
[LLat. obfuscare, to darken : ob(intensive) + Lat. fuscare,
to darken < fuscus, dark.] -obfuscation n. obfuscatory adj

What is obfuscated code?

It is a machine code that is written in a peculiar way can hardly be understood by us human beings.

What is the Morse code?

morse is a system that is used to encrypt a language generated by sounds formed by dots which translates characters

The following code was written by Jim Hague (UK), it was IOCCC winner, 1986.

#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;}

What is this ???

This code accepts the ASCII for the standard input and outputs the morse code.

What does this do?

C has two types of macros, objects- like macro and function-like macro. when the code goes to compilation, in the first step of compilation is preprocessor, the GCC compiler will remove all comments, including the header files, and expand the macros, replace the left side macro name with right side of contents, but If the expansion of a macro contains its own name, either directly or via intermediate macros, it is not expanded again when the expansion is examined for more macros. This prevents infinite recursion. we use the flag -E to tell GCC only preprocessor and make the *.i file.

When we compile the code we’ll see the below output:

now use gcc hague.c -o h …

you can write anything and it will appear in morse code characters like this below :

Let’s replace the macros, so the code will looks like that

/* take the array of ASCII values */
char _DAH_[] = "ETIANMSURWDKGOHVFaLaPJBXCYZQb54a3d2f16g7c8a90l?e'b.s;i,d:";/* function main */
main ()
{
char *_DIT, *DAH_, *DIT_, *_DIT_, *malloc (), *gets ();/* in this loop takes the line of input and prints a new line after finish */ for (_DIT = malloc (81), DIT_ = _DIT++; _DIT == gets (_DIT); __DIT ('\n'))/* in nested for loop, check if current character is in _DAH_, if so call conversion; otherwise, print '?' */
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 - convert to morse code */_DAH (DIT_)
{
__DIT (DIT_ > 3 ? _DAH (DIT_ >> 1) : '\0');
return DIT_ & 1 ? '-' : '.';
}/* __DIT - print to standard output*/__DIT (DIT_)
char DIT_;
{
(void) write (1, &DIT_, 1);
}

This code works and we see the three functions main, _DAH, and __DITand the output will be part of the argument printed as and . masking for 1 and 0 , i.e. the number in binary format, and it will return the second leftmost digit. As an example, if we call _DAH(5) , 5 being 101 in binary, it will call _DAH(2) .

char ascii_array[]="ETIANMSURWDKGOHVFaLaPJBXCYZQb54a3d2f16g7c8a90l?e'b.s;i,d:";main ( )
{char * _dot,* _dash,* _2_dot,* _3_dot,* malloc (),* gets ( );
for( _dot = malloc ( 81 ), _2_dot = _dot++; _dot == gets ( _dot ); print('\n') )
for ( _dash = _dot; *_dash; print ( *_3_dot ? convert ( * _2_dot ) : '?'), print(' '), _dash ++ )
for (* _2_dot = 2, _3_dot = ascii_array;* _3_dot && (* _3_dot != ( * _dash >= 'a' ? * _dash & 223 : * _dash ) );(* _dot ) ++, _3_dot ++ )* _2_dot+= ( * _3_dot >= 'a'? * _3_dot-'a' : 0);}convert ( _2_dot ){print (_2_dot > 3 ? convert ( _2_dot >> 1 ) : '\0');return _2_dot&1 ? '-' : '.';}print ( _2_dot ) char _2_dot;{( void ) write ( 1,&_2_dot,1 );}

Writing code can sometimes be the most difficult part of any software development process. If you don’t organize everything from the start — especially for big projects — the coding processes and code management afterward may end up not just time consuming, but also a big headache.

--

--