views:

84

answers:

3

I'm trying to learn C from a Ruby/PHP/Java background, and I've found that you almost always explicitly cast things (at least in tutorials). Like, I always see things like

double x, y;
x = 1.0; 
/*...*/
y = x*5.0;

However, it seems that on my Mac's version of GCC, automatic casting works.

Is leaving the .0 on things just a matter of style, or do some C compilers not autocast?

A: 

Autocasting only works when you add precision (or at least don't lose any), e.g. int -> float, int -> char, char -> int.

Going the other way requires casting, since it is up to the programmer to decide how to lose precision. Typically this is done by flooring, but specific applications may call for randomly flooring and ceiling.

Leaving .0 is not a matter of style. It can be important; try displaying 3/5 and 3.0/5.0. They are very different.

mcandre
Nitpicking: the conversion from `int` to `float` can lose precision. But this is usually considered acceptable.
Roland Illig
Casting is not *required* for lossy conversions for successful compilation, the compiler may generate a warning.
Clifford
@Roland Illig: float is good for 7 significant decimal digits, so any integer than 9999999 may not be stored exactly; as you say that may be acceptable, but you need to understand it to make that judgement.
Clifford
Roland: true, true. For very large positive/negative ints, this can happen.
mcandre
@Clifford: ISO C99 says in 5.2.4.2.2p8: "`FLT_DIG >= 6`", so even a 7-digit integer number may be too big to be stored in a `float`.
Roland Illig
@Roland Illig: Well 7 *is* >= 6. ;) That value defines the minimum acceptable in a conforming implementation. An IEEE-754 single precision value has between 6 and 9 significant digits depending on magnitude. So over the range you are correct. I checked first (and was going to say 6), but apparently either misread or hit an unreliable source.
Clifford
@mcandre: A seven digit integer is not *that* large. I just performed a test and 16777216 is the highest positive integer for which that and all smaller values can be stored precisely as a float. So all 7 digit integers and a few 8 digit values too; so my earlier assertion turned out to be accurate.
Clifford
@Clifford: Maybe that works on your particular system (probably IEEE 754 with 32-bit int). But it is not guaranteed by ISO C99. That only guarantees you 6 digits of precision.
Roland Illig
@Roland Illig: I think that is exactly what I said (in the previous comment). No argument from me. The FPU of every modern processor in general use that I can think of uses IEEE 754, so the argument is somewhat academic.
Clifford
+1  A: 

When an implicit cast is unsafe (may cause loss of bits or precision), your compiler should warn you unless you have set too low a warning level. Alarmingly perhaps, in VC++ this means warning level 4 when the default is 3.

An explicit cast will suppress such warnings, it is a way of telling the compiler you are doing it intentionally. If you liberally apply casts without thinking you prevent the compiler from warning you when the potential loss of data or precision is not intentional.

If you have to cast, you should consider whether your data has the appropriate type to begin with. Sometimes you have no choice, or it is a convenient way of adapting to third-party code. In such cases an explanatory comment may be in order to make it clear that you really did think about it and not just habitually applying a cast.

Clifford
+6  A: 

A constant has the type it is being assigned to:

int i = 1;
double x = 2; // 2.0

explicit cast:

i = (int)x;
x = (double)i;

implicit cast:

i = x;
x = i;

type promotion:

x = i / 2.0; // i is promoted to double before being multiplied
x = (double)i / 2.0; // so evaluates as this

vs

x = i / 2; // i is not promoted because 2 is an int
x = (double)( i / 2 ); // so evaluates as this
drawnonward
Your type promotion example is not quite right - the constant `2.0` has type `double`, not `float`, so the type promotion is to `double` also.
caf
@caf Fixed, thanks
drawnonward
A constant doesn't have the type it is being assigned to, it has its own type before assignment. The assignment may promote the value through an implicit conversion, but that doesn't affect the type of the constant. (Actually 'literal' is more appropriate than constant in your example).
A. Levy