[On using casts vs using temporary variables]
Clarity of purpose is one important item.
Another, admittedly minor, problem is that assignment introduces an
alias - two variables pointing to the same memory. Other things being
equal, that is undesirable.
I think this is not exactly "minor" either.
Code generally has two functions:
- It should be an unambiguous set of directions to a computer, and
- It should provide sufficient clues to later programmers (who
may be the original code-writers, or others) so that they can
understand not only *what* is to be done but *why* it is being
done.
My own take on casts vs temporaries is a specialization of a more
general rule:
If something is important, give it a *name*. If it is going
to be used frequently, give it a name. If it is unimportant
*and* will appear rarely (especially "just once"), try *not*
to give it a name.
Casts create temporary values but do not give them names -- so
they should be avoided if you will use the result more than once.
Hence, in a typical qsort comparison function, where we need to
use the arguments several times, we should avoid casts. The
arguments arrive with the "wrong" type, so we must create pointer
aliases, despite their drawbacks.
/*
* Compare XYZs for qsort. Returns 0 if the left and right
* side XYZs are equal, -1 if the left XYZ is "less than"
* the right XYZ, and 1 if the left XYZ is "greater than" the
* the right.
*/
int xyz_compare(const void *l0, const void *r0) {
const struct xyz *l = l0;
const struct xyz *r = r0;
if (l->firstkey != r->firstkey)
return l->firstkey < r->firstkey ? -1 : 1;
if (l->secondkey != r->secondkey)
return l->secondkey < r->secondkey ? -1 : 1;
...
return 0;
}
To emphasize the fact that "l" and "r" (left and right) are
the "real" arguments, and the parameters simply come in with
the "wrong" type (void *), the parameters are named "l0" and
"r0" and the function "strips off the zeros" when converting
the arguments to the correct type.
I also tend to use this "x sub zero" notation for preserving
arguments that will be modified inside the function: x0 is the
original (input) value of x, which is then changed as needed, with
the original value still available as needed. This provides the
relation between the variables (both are "x") as well as the
"sequence" aspect: x sub 0 is the original, x sub i is the i'th if
we have to preserve additional values, and x is the current one if
we want a short name for it. (In another language this might be
bad since "x" could refer to the entire vector, but C is not APL.

)