C Programming Tidbits

Sometimes I have to rack my brain for the correct way to do something in C. This is a collection of tidbits that are, to the best of my knowledge, the right way to do things.

Links

Why C is not my Favourite Programming Language.

Portability

Good luck finding a consistent C standard that contains the functions you use. (Of course, C99 doesn't contain strdup. Why would it?). I have an ongoing project documenting portability goo as I encounter it.

Correct use

Some C functions are designed to be misused. Here are some of my least favorites:

strncpy

Problem: it returns an int. It *should* return a size_t, or at worse, ssize_t (since it also returns a -1 on error). Proper use is likely something like:

  char *buf[100], *bar;
  int n;

  ...
  
  n = snprintf(buf, sizeof(buf), "buffer: %s", bar);
  if (n < 0 || n >= sizeof(buf))
    /* handle error */

An explicit test against -1 (if (n == -1 ...)) is probably also safe, since the only sane thing snprintf can do when asked to copy more than INT_MAX characters is to return an error.

Bitfields

Set / Clear bits

Assume we are using a 32-bit unsigned type called uint32. We can set or clear bit i using the following:

  bits[i / 32] &=  ~((uint32)1 << (i & 31)); 
  bits[i / 32] |=  (uint32)1 << (i & 31); 

Note that the typecast on the 1 becomes very important when dealing with types longer than an int (i.e. long long). Most compilers will implicitly assume 1 is an int, so shifting it by 32 positions or more will not have the desired effect (where int == 32 bits).

Also note that the range on the shift operators appear to be (for an n-bit quantity) 0 ... n-1. The expression:

 uint u32, i;

 i = 32;
 u32  = u32 << i;

appears to have no effect. The value in u32 is simply not shifted. (noted on a linux box with gcc 2.96).

pintday.org » Fresh every Tuesday.