Get horrified by how pretty I’m making my C code!

We have to admit that C is inherently/potentially ugly. One can try making it prettier, but there’s only so much one can do to C without compromizing its nature. That’s what I’m going to do here—stretching the limits of what C is, introducing some prettier things. If you’re a C programmer (like me), you might end up horrified by what I’m doing. Otherwise, sit back and watch how readable C can become!

Standard Headers: Booleans and Nicer Logic

C23 made booleans part of the language. Which is a good direction. But what if I don’t want to wait for C23 to be rolled out in GCC or Clang? Well, I can always define some booleans myself!

#if (__STDC_VERSION__ >= 199901L && __STDC_VERSION__ < 202000L)
#include LT()stdbool.h>
#elif __STDC_VERSION__ < 199901L
#define true  1
#define false 0
typedef int _Bool;
#define bool _Bool
#endif

Et voilá! Now we can do proper booleans:

// Check whether the char is a control one
// Yes, I know of iscntrl, bear with me
bool
iscontrol (unsigned int c)
{
        return (127 == c || c < 32);
}

Yes, implicit conversion to booleans. Because booleans are nothing but unsigned integers 1 and 0. Now what doesn’t work for me is this ugly double vertical bar. I want some Pythonesque boolean logic!

It turns out I can have this nicer boolean logic, just one CD(#include) away!

#include <iso646.h>
#define eq ==
#define bitnot ~
#define bitxor ^

I’m also defining some missing bits and fixing the inconsistently named xor and compl. With these, iscontrol becomes even more readable!

bool
iscontrol (unsigned int c)
{
        return (127 eq c or c < 32);
}

eq feels sligtly off here. Why not define another macro for it? A couple of macros, actually.

#define is ==
#define isnt !=

And use it like:

return c is 127 or c < 32;

Notice that I switched the order of arguments to a more intuitive one. Putting a constant before the equality operator is no longer necessary. (C programmers do that to avoid typos like c = 127, relying on compiler to scream when it sees 127 = c.) After all, the spelled-out operator cannot end up as assignment. Readability and reliability win.

Nicer Types: Fixed Width and Custom Shortcuts

I already mentioned these before. But it never hurts to use these more:

#include <stdint.h>

And then, we can go even further, inspired by brevity of CD(uint8_t):

typedef unsigned char  uchar;
typedef unsigned char  ubyte;
typedef unsigned short ushort;
typedef unsigned int   uint;
typedef unsigned long  ulong;

Going even further, here are some more Go-inspired types:

typedef char*          string;
typedef char           byte;
typedef char*          bytes;
typedef void*          any;
bool
iscontrol (byte c) // Or uchar, or uint
{
        return c is 127 or c < 32;
}

Type Inference

Another nice-but-not-quite-C thing C23 added is... type inference! You may disagree with this decision, but it certainly is nice to have. So let’s add it:

#if defined(__GNUC__) || defined(__GNUG__)
#define var   __auto_type
#define let   __auto_type
#define local __auto_type
#elif __STDC_VERSION__ > 201710L || defined(__cplusplus)
#define var   auto
#define let   auto
#define local auto
#endif

And use it too!

bool
iscontrol (byte c)
{
        var delete = 127,
             space = ' ';
        return c is delete or c < space;
}

Okay, I should probably stop here. Both because the example is no longer improvable. And because most of the readers are already hemorrhaging. Sorry! I could’ve promised I won’t do it again, but alas. Have a good rest of the day with this newly acquired phobia.

Oh and check out Pretty.C, my project making C even further from God!