Casting
From C
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