1) One should aviod using casts while writing a program that is
supposed to be portable. casts are sign of bad design.
Let's be a bit more pedantic and restrict that to pointer casts.
Casting "normal" values is quite common, you may often see in C89
programs e.g.
char hw[ ] = "Hello world!";
printf( "%lu\n", ( unsigned long ) strlen( hw );
to convert the size_t type return value of strlen() to something you
can print with one of the available format specifier (in C99 you bet-
ter would drop the cast and use "%zu" in the format string instead) or
double d = 42.1234;
int i = ( int ) d;
to assign the integer part of 'd' to 'i', snipping off the fractional
part.
And while casting pointers is often a sign of some trouble in a program,
there exist a few cases where they it's actually required, mostly in
conjunction with arguments of variadic functions. Take the following
(admittedly rather contrived) example program:
#include <stdio.h>
#include <stdarg.h>
double add_to( double stuff, ... )
{
va_list ap;
double *dp;
va_start( ap, stuff );
while ( ( dp = va_arg( ap, double * ) ) != NULL )
stuff += *dp;
va_end( ap );
return stuff;
}
int main( void )
{
double d0 = 1.0,
d1 = 2.0;
printf( "%f\n", add_to( 0, &d0, ( double * ) NULL ) );
printf( "%f\n", add_to( 0, &d0, &d1, ( double * ) NULL ) );
return 0;
}
The add_to() function takes a double argument plus an unspecified num-
ber of double pointers and then adds all the values the pointers are
pointing to to the first argument, returning the result. The end of
the argument list is marked by a NULL double pointer.
You may have noticed that I wrote "NULL double pointer" and not just
"NULL pointer" in the last sentence. That's because a "NULL double
pointer" could have a different bit representation than e.g. "NULL
void pointer", and it's simple values in a certain bit representation
tha get passed to functions. When you have a function foo() which is
declared as
void foo( double *dp );
and you call it like this
foo( NULL );
then the compiler knows that foo() expects a double pointer and will
convert NULL to a value with the correct bit representation for a
"NULL double pointer" and not the bit representation for e.g. a "NULL
void pointer" if the representations differ (that's another reason
why having correct function declarations can be so important).
But there's a snag with the add_to() function - the compiler doesn't
know about the types of the arguments following the first one. So
when calling add_to() the compiler can't help you by automatically
converting pointers if necessary and it's then your obligation to
make sure pointers of the correct type get passed to the function.
And that's why in the call
add_to( 0, &d0, ( double * ) NULL )
the NULL pointer actually must be cast - without the cast, the function
would be called with a value which is the bit representation of a "NULL
void pointer" and not necessarily the required representation of a "NULL
double pointer". So this is a place where a pointer cast isn't a mistake
but required. (Of course, one may argue that a design of that kind is
bad, but sometimes there may be no better solution.)
2) Sometimes while writing a piece of code that has to
directly access h/w (device drivers, embedded s/w) casts may be
the only option. In such cases, one must be aware of the consequences
of typecasting. Also, in such cases code review is the best
tool to find out such bugs. Compiler may not be issuing the
warning for all such *incompatible* casts.
The compiler probably won't issue a warning for whatever cast (except
for casts of function pointers to object pointers) since a cast tells
it that you know better - why would you use the cast otherwise?
Still I have one question. I might sound irritating but its better to
ask. Please bear with me. As most of you said that the compiler
didn't generate any warning because it was explicitly told to do
so. But there are other cases as well where explicit cast is done,
still the complier gives the warning.
eg.
int main(void) {
char * c_ptr;
int * i_ptr;
(int *)i_ptr = (char *) c_ptr; /* warning for this line */
return(0);
}
compiling this code always generates warning.
Something must be wrong with your compiler since this shouldn't just
generate a warning but an error message. You can't use a cast like
that on the left hand side of the assignment, it's like writing
int x;
-x = 3;
On the left hand side of an assignment you always have to have an ex-
pression that, when evaluated, must designate an object. And like "-x"
is not an existing object, so also "(int *) i_ptr" does not designate
an existing object (the result of the cast is a pointer value, not an
object). It's not like e.g.
*( (int *) i_ptr ) = 3;
where the computed value of the expression designates an object (a
memory location) a value can be assigned to (at least if 'i_ptr'
points to some memory you have permission to write to and that the
alignment requirements are satisfied).
Let's hope I got that right, otherwise someone more knowledgeable will
chime in.
Regards, Jens