.TH SELF 7 .SH NAME c-not-c \- C Until It Is No Longer C .SH AUTHOR Artyom Bologov .SH SYNOPSIS Get horrified by how pretty I’m making my C code! .SH TEXT .P We have to admit that C is \fBmaking-c-uglier (7)\fP inherently/potentially ugly. One can try \fBmaking-c-prettier (7)\fP 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! .SH Standard Headers: Booleans and Nicer Logic .P 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! .P .in +4n .EX #if (__STDC_VERSION__ >= 199901L && __STDC_VERSION__ < 202000L) #include #elif __STDC_VERSION__ < 199901L #define true 1 #define false 0 typedef int _Bool; #define bool _Bool #endif .EE .in .P — Making booleans accessible on every version of the standard .P Et voilá! Now we can do proper booleans: .P .in +4n .EX // 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); } .EE .in .P — Using booleans .P 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! .P It turns out I can have this nicer boolean logic, just one \fB#include\fP away! .P .in +4n .EX #include #define eq == #define bitnot ~ #define bitxor ^ .EE .in .P — iso646 and some more aliases .P I’m also defining some missing bits and fixing the inconsistently named \fBxor\fP and \fBcompl\fP. With these, \fBiscontrol\fP becomes even more readable! .P .in +4n .EX bool iscontrol (unsigned int c) { return (127 eq c or c < 32); } .EE .in .P — iso646 macro use .P \fBeq\fP feels sligtly off here. Why not define another macro for it? A couple of macros, actually. .P .in +4n .EX #define is == #define isnt != .EE .in .P — Defining (in)equality .P And use it like: .P .in +4n .EX return c is 127 or c < 32; .EE .in .P — iso646 macro use .P 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 \fBc = 127\fP, relying on compiler to scream when it sees \fB127 = c\fP.) After all, the spelled-out operator cannot end up as assignment. Readability and reliability win. .SH Nicer Types: Fixed Width and Custom Shortcuts .P \fBmaking-c-prettier (7)\fP I already mentioned these before (section types-and-constants). But it never hurts to use these more: .P .in +4n .EX #include .EE .in .P — Including fixed-width types like int32_t .P And then, we can go even further, inspired by brevity of \fBuint8_t\fP: .P .in +4n .EX typedef unsigned char uchar; typedef unsigned char ubyte; typedef unsigned short ushort; typedef unsigned int uint; typedef unsigned long ulong; .EE .in .P — Defining shorter aliases for standard types .P Going even further, here are some more Go-inspired types: .P .in +4n .EX typedef char* string; typedef char byte; typedef char* bytes; typedef void* any; .EE .in .P — More shortcut/convenience types .P .in +4n .EX bool iscontrol (byte c) // Or uchar, or uint { return c is 127 or c < 32; } .EE .in .P — Using new “byte” type .SH Type Inference .P 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: .P .in +4n .EX #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 .EE .in .P — Defining auto-inferred variable definition macros .P And use it too! .P .in +4n .EX bool iscontrol (byte c) { var delete = 127, space = ' '; return c is delete or c < space; } .EE .in .P — Using type-inferred vars .P 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. .P Oh and check out .UR https://github.com/aartaka/pretty.c Pretty.C .UE , my project making C even further from God! .SH COPYRIGHT .UR https://creativecommons.org/licenses/by/4.0 CC-BY 4.0 .UE 2022-2026 by Artyom Bologov (aartaka,) .UR https://codeberg.org/aartaka/pages/commit/a91befa with one commit remixing Claude-generated code .UE . Any and all opinions listed here are my own and not representative of my employers; future, past and present.