K&R (1st ed.) is vague about the difference, but every `natural'
conversion will happen across an assignment, and only pointer
conversions require casts here. This includes pointer-to-integral,
integral-to-pointer, and pointer-to-T1 to pointer-to-T2 wherever T1 and
T2 are distinct types. Structure and union conversions are illegal
whether cast or not.
In other words, an explicit cast is only required when one or more of
the following hold:
- there is no implicit cast
- the implicit cast would cause at least a warning
- the explicit cast is to a different type than the implicit cast
(in which case the explicit cast is followed by the implicit cast)
The last case is something like
i = (unsigned char)s;
which moves the value in `s' through four(!) types before reaching
`int' and storing in `i':
s short, lvalue
<sign extended value>s int, rvalue
<truncated value>s unsigned char, rvalue
<expanded truncated value>s unsigned int, rvalue
The last type may be (but is not necessarily) different under the dpANS
C `value preserving' rules: (unsigned char) expands to (signed int),
unless the number of bits in an unsigned char is greater than or equal
to the number of bits in a signed int. Since the number of bits in a
char (signed or not) may not be greater, the type is either (signed int)
or (unsigned int) depending on whether sizeof(char)==sizeof(int).
This is conceptually grotesque, but makes little difference in practise.
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain: ch...@mimsy.umd.edu Path: uunet!mimsy!chris
I understand that there are some compilers that do not do the
truncation properly. In other words,
int i = (unsigned char)0xFFFF;
stores 0xFFFF in i, instead of 0xFF (assuming 8 bit bytes, of course).
Such compilers are broken, but if portability is a concern, one
should avoid assuming that casting (or for that matter, assigning to
a char) properly truncates a value.