Coding tips they don't teach you in school

Here are some C coding tips, because I have been unable to post anything for a while.

Some of these time-saving shortcuts are intended for small projects or prototyping code.

The nested ? : trick

The switch statement is very efficient, and the compiler will often implement it as a table lookup so it doesn't have to do any comparisons. But it sure can tire your fingers in a hurry:
switch( number ) {

    case 1: str = "one"; break;
    case 2: str = "two"; break;
    case 3: str = "three"; break;
    case 4: str = "four"; break;
    case 5: str = "five"; break;
    default: str = "unknown number"; break;
}

If getting the code out is more important than its speed, you can use a nested conditional operator to save typing:

str = number == 1 ? "one" : 
      number == 2 ? "two" :
      number == 3 ? "three" :
      number == 4 || rand() == 42 ? "four" :
      number == 5 ? "five" :
      "unknown number";

You can freak out your coworkers if you do it all on one line.

DeMorgan's theorem of negativity

// if blah blah blah blah blah blah....
if ( !(A && B) )

is the same as

// if blah blah
if ( !A || !B )

Pick the one that is easier to understand and read out loud. It is usually the second.

Rounding numbers using integer math

Suppose you have 2001 boolean variables, so you want to keep them in a bitmap of bytes, 8 at a time. How do you declare this array?

#define NUMBER_OF_BITS 2001
unsigned char bitmap[ NUMBER_OF_BITS / 8 ]; // FAIL!

The computer uses integer math, so 2001 / 8 is 250 and there is one bit left over. When you store bit 2001, you will corrupt memory. You can round numbers up like this:

unsigned char bitmap[ (NUMBER_OF_BITS + 7) / 8 ];

This works because integer division always rounds down. However, if you add the divisor less one, then you will force it to always round up. It will also work for 32 bit integers:

unsigned int bitmap[ (NUMBER_OF_BITS + 31) / 32 ];

Real rounding via integer division

Adding something before dividing is a general technique. This code rounds a and b to the nearest 10.
int a = 12;
int b = 16;

printf("Round a: %d", (a + 5) / 10 * 10 );
printf("Round b: %d", (b + 5) / 10 * 10 );

Multiply by arbitrary numbers using shift

Sometimes, for good reasons, you need to hand optimize your code. But most of the time, somebody is just showing off, and you will see code like this:

b = ( a << 1 );

This is the same as multiplying by 2. Because of the way binary numbers are represented, you can multiply by any power of two by shifting by that power. You can also multiply by other numbers.

// b = 10*a, which is 8*a + 2*a
b = ( a << 3 ) + ( a << 1 );

Division isn't as nice looking.

Getting array sizes

In C, you can get the total size of an array in bytes using the sizeof operator. Dividing it by the size of each element will give you the number of elements in the array.
MyHugeStructure array[100];
int i;

for( i = 0; i < sizeof(array)/sizeof(*array); i++ ) 
{
    array[i].id = i;
}
The downside is that if you ever change the array to be dynamically allocated using new or malloc(), then sizeof() will only return the pointer size. Of course, in a large project you should have have a defined constant for the number of entries.

Else Flattening

Deeply nested else clauses are hard to understand. But if they look like this, you are in luck:

if ( A ) {

} else {
   if ( B ) {

   } else {
       if ( C ) {

       }
   }
}

Save money on wide screen monitors by flattening the elses.

if ( A ) {

} else if ( B ) {

} else if ( C ) {

}

Black is White and Up is Down if you're not using a mainstream compiler

If your code has to run on a lot of different platforms, you should know that GCC and Microsoft VC++ are very similar and this similarity will trick you into thinking that all compilers are alike. But the C standard leaves a lot of stuff out that will surprise you, if you do work on embedded systems with crappy, but standards-conforming compilers.

What is sizeof(char)? In most compilers it is 1 byte. Switch compilers, and it might be 2 or 4 bytes. The C standards only says that it cannot be larger than an int.

What happens if you add something to the maximum integer?

int a = MAX_INT;
a++;
printf("%dn", a);

In mainstream compilers you get a negative number, since the number space wraps around. But the C standard says the result is undefined. So some compilers will leave a at the maximum value, MAX_INT.

And don't even think about bit-shifting a negative number:

int a = -2;
printf("%dn", a >> 1 );

Comments