/* * title C * author "Dylan Lom" * link stylesheet /main.css */ # $(echo $title) I think C is a pretty good programming language. But there's a lot of "old knowledge" in C -- the sort of stuff that you only really learn by reading through actual code bases, I thought I'd leave some tips I've found here. ## Zero-initialization From the standard: > If there are fewer initializers in a brace-enclosed list than there > are elements or members of an aggregate, or fewer characters in a string > literal used to initialize an array of known size than there are elements > in the array, the remainder of the aggregate shall be initialized > implicitly the same as objects that have static storage duration [C99 Standard Draft](http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf), Section 6.7.8, Point 21 Looking at point 10 just above that we will see that this means initialized to `NULL/0`. This gives way to the common practive of doing something like ``` int f(int k) { struct myStruct = { 0 }; // ... } ``` Which gives us a nicely zero-initialized variable on the stack (same applies for arrays, etc.). This ruling also applies if you just wanted to initialize one or two members to non-zero. ## Enums for better arrays. Here's a trick I learnt from [sfeed](https://git.codemadness.org/sfeed/), you can use an enum to name the members of some data stored in an array. As a bonus you can add a `COUNT` member which will be the size of your array to read the whole blob into it. ``` enum { PKT_HEADER = 0, PKT_BYTE1, PKT_BYTE2, PKT_BYTE3, PKT_CHECKSUM, PACKET_COUNT }; // ... unsigned char data[PACKET_COUNT]; fread(data, sizeof(*data), PACKET_COUNT, fp); printf("Byte 1: %hhu\n", data[PKT_BYTE1]); } ``` I could see people at work complaining this is horrible design, but I quite like it :) ## Better sizeof Taking a look at the snippet above, you might've also noticed that the `size` parameter that I pass to `fread(3)` is coming from the size of whatever our variable points to indirectly. This means we don't have to copy-paste the data type into the sizeof and get a codebase that would work if we started using a different-sized data type (obviously in this example it wouldn't make a tonne of sense for that to happen -- but I think it is an improvement here anyway). ## ASAN + LeakSanitizer The address sanitizer will make debugging segfaults actually viable (`-fsanitize=address`), and should absolutely be enabled during development. The leak sanitizer will also catch a lot of memory leaks (direct & indirect) and will probably encourage you to fix them now instead of later (which you should). In my version of `gcc`, enabling ASAN also turns on LSAN. ## Assert often This isn't really a C-specific piece of advice but I think it's something that most people overlook -- assertions are like breakpoints baked into your program to stop you doing stupid shit. This is especially helpful when the language doesn't `throw` exceptions when you do said stupid shit. I also really like using them if I'm stubbing out functions -- leave an `assert(0 && "TODO: Implement this thing")`, and that way you can safely forget about that stub until you need it.