C

C

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, 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, 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.