Notes about the C and C++ programming languages.
Useful features for the IOCCC:
Whenever you use array[index] it can be replaced with index[array]:
array[index] ==*(array + index) == \*(index + array) == index[array]Need an obscure way of writing a constant zero? Try ’-‘-‘-‘:
‘-‘-‘-‘ == ‘-‘ - ‘-‘ == 45 - 45 == 0others?
Other tricks:
The ‘xor trick’ for a doubly-linked list
struct node { void *data; size_t refs; }; struct list { struct node *start; struct node *end; }; struct list *createList() { return (struct list*)malloc(sizeof struct list); }; struct node *createNode(void *data) { struct node *newnode = (struct node*)malloc(sizeof struct node); newnode->data = data; newnode->refs = 0; return newnode; } void appendList(struct list *list, node *data) { data->refs = (size_t)list->end; list->end->refs ^= (size_t)data; list->end = data; } struct node *elemAtList(struct list *list, int idx) { struct node *prevPtr = 0; struct node *ptr = start; while (idx— && ptr) { struct node *temp = ptr; ptr = ptr->refs ^ prevPtr; prevPtr = temp; } return ptr; }The above isn’t overly useful, but the mechanism to extend this to allow forward and back iterators is fairly obvious :D
Compile time sanity checking in C/C++
#define COMPILER_ASSERT(x) char name_noone_will_use[(x)?1:-1]; name_noone_will_useAnd this will work for any statically evaluable expression x
Note that with macros like the above, its often a good idea to use the do/while(0) trick:
#define COMPILER_ASSERT(x) do { char foo[(x)?1:-1]; foo; } while(0)
This prevents weird compiler errors when doing this:
if(bar)
COMPILER_ASSERT(x);
else
wibble();
If the first version of the macro is used then the compiler will complain about a dangling else, since only the first statement in the macro will be attached to the if. Just putting the curly braces in the macro won’t work since the semicolon at the end will get interpreted as a statement and the same problem will occur. Having the do/while(0) doesn’t affect performance since just about every C compiler, even gcc, can optimise it out. —Ryan
“Duff’s Device”
Occasionally we can find ourselves writing code like:
void copy(char* target, const char* src, size_t count) { while (count—) *target++ = *src++; }Obviously this implies N branches and N conditional checks. Happily Duff’s Device gives us a way out:
void copy(char* target, const char* src, size_t count) { size_t n = (count + 4) / 5; switch (count % 5) { case 0: while (n—) { *target++ = *src++; case 4: *target++ = *src++; case 3: *target++ = *src++; case 2: *target++ = *src++; case 1: *target++ = *src++; } } }We can see cleary that this reduces both the branches and the conditional checks by a factor of 5. While I have used a modulus of 5 in this example (to keep everything clear), real world use would use a power of two thus allowing the modulo and division operations to be replace with bitops. Duff’s Device can be trivially applied to for-loops, etc (this is left as an exercise for the reader).
Caveat: in some cases the increased code size caused by Duff’s Device can blow the instruction case, thereby reducing performance.
—Ollie
Named struct initialisations
Heres a trick I learned recently that surprised Ollie and I since neither of us had seen it before, even though its available in c99 and used in the Linux kernel. Given a struct definition such as: struct foo_t { char *name; int value; }
You can initialise it like this:
struct foo_t bar = { .name = “a bar”, .value = 20 };
which is arguably nicer than the c89 way (although Ollie complains the . prefix is ugly). The really cool thing is that you can do partial initialisations, i.e. just giving values to some of the fields, and they don’t have to be in any particular order.
—Ryan
That is really useful looking. If only i wrote more C. brehaut
Looks much like erlang’s records which are initialised like:
X#foo_t{name=”a bar”, value=20}
(where X is the varname). âmattw
