Casting

From C

Jump to: navigation, search

When not to cast

Casting is to be avoided if possible; it can lose data, or hide errors (See the discussion re. malloc() in Tips and http://www.c-faq.com/malloc/mallocnocast.html).

Here are some typical scenarios where beginning C programmers will use unecessary casts, and how to avoid them.

  • When an operation will yield a result of a type that loses information (think dividing integers)
In this case, no cast is required:
int a = 7;
double f = a / 2.0;  /* instead of a / 2 */
Some will use a cast for this:
double divide(int a, int b)
{
  return a / (double)b;
}
But no cast is necessary:
double divide(int a, int b)
{
  double f = a;
  f /= b;
  return f;
}
  • When something is expecting an object of a particular type, but it may be implemented in such a way that implicit type casting doesn't take place.
Casting is not necessary in this case either. Consider writing a comparison function for qsort():
int compare_int(const void *a, const void *b)
{
  const int *p1 = a, *p2 = b;
  if (*p1 < *p2) return -1;
  else if (*p1 > *p2) return 1;
  else return 0;
}
...
int a[] = { 7, 5, 3, 4, 2 };
qsort(a, sizeof a / sizeof *a, sizeof *a, compare_int);
The key here is to use a pointer of the right type, converting the void pointer value to it before using it.
  • For implementing wacky forms of polymorphism.
I'm not sure what this means, but I'll bet casting isn't required here either.
Converting any object pointer to void pointer requires no cast. C performs this conversion implicitly:
 void *ptr = &x;
Converting a pointer value from void pointer type to its original object type is also well-defined:
double f, *p;
void *x;
x = &f;  /* convert (double *) to (void *) */
p = x;   /* convert (void *) to (double *) */

When to cast

A cast is required when there is no way for C to determine the proper type.

When passing certain argument values to variadic functions, a cast is required.

printf("%p\n", (void *)&myobj);

Here, the %p conversion specifier expects a void pointer value, so the argument must be converted. Of course, this cast can be avoided:

void *tmp = &myobj; printf("%p\n", tmp);

Another example from the POSIX world:

execl("/bin/cat", "/bin/cat", "/tmp/Foo", (const char *)0);


See also Richard Heathfield's page on casting: http://www.cpax.org.uk/prg/writings/casting.php

Personal tools