Casts

J

jacob navia

Hi

I am still writing my tutorial book about C. Here is the section about
casts. I would be interested in your opinions about this. Some people
have definite views about this subject ("never use casts") some others
(like me) are more "liberal" in this subject. I would be interested
in any feedback.

jacob
-------------------------------------------------------------------
Casts
A cast expression is the transformation of an object from one type to
another. For instance, a common need is to transform double precision
numbers into integers. This is specified like this:
double d;
....
(int)d
In this case, the cast needs to invoke run time code to make the actual
transformation. In other cases there is no code emitted at all. For
instance in:
void *p;
....
(char *)p;
Transforming one type of pointer into another needs no code at all at
run-time in most implementations.

When to use casts

A cast can be useful to avoid unnecessary operations. For instance,
given the declarations:

double double_value;
int integer_value;

If you write

integer_value /= double_value;

The integer is promoted to double to do the division, then the result is
converted to integer again. With a cast however, the unnecessary
promotions can be avoided:

integer_value /= (int)double_value;

You can use a cast expression in another context, to indicate the type
of a composite constant literal. For instance:
typedef struct tagPerson {
char Name[75];
int age;
} Person;

void process(Person *);
....
process(&(Person){“Mary Smith” , 38});
This is one of the new features of C99. The literal should be enclosed
in braces, and it should match the expected structure. This is just
“syntactic sugar” for the following:

Person __998815544ss = { “Mary Smith”, 38};
process(&__998815544ss);

The advantage is that now you are spared that task of figuring out a
name for the structure since the compiler does that for you. Internally
however, that code represents exactly what happens inside lcc-win32.

When not to use casts

Casts, as any other of the constructs above, can be misused. In general,
they make almost impossible to follow the type hierarchy automatically.
C is weakly typed, and most of the “weakness” comes from casts expressions.

----------------------------------------------------------------------
 
E

Eric Sosman

jacob said:
[...]
A cast can be useful to avoid unnecessary operations. For instance,
given the declarations:

double double_value;
int integer_value;

If you write

integer_value /= double_value;

The integer is promoted to double to do the division, then the result is
converted to integer again. With a cast however, the unnecessary
promotions can be avoided:

integer_value /= (int)double_value;

It would be worth mentioning that the modified expression
may produce a different value than the original. For example,
consider integer_value=10 and double_value=3.5, where the
original code calculates 2 and the revised code calculates 3.
(Even better: consider double_value=0.1 ...)
You can use a cast expression in another context, to indicate the type
of a composite constant literal. For instance:
typedef struct tagPerson {
char Name[75];
int age;
} Person;

void process(Person *);
...
process(&(Person){“Mary Smith” , 38});

This is not a cast, so it doesn't belong in a tutorial
about casts. (Except, perhaps, to explain that it is not
a cast despite a faint and superficial syntactic resemblance.)
 
M

Malcolm McLean

jacob navia said:
Hi

I am still writing my tutorial book about C. Here is the section about
casts. I would be interested in your opinions about this
void process(Person *);
...
process(&(Person){“Mary Smith” , 38});
This is one of the new features of C99. Internally however, that code
represents exactly what happens inside lcc-win32.
I think you should either write a C89 tutorial, a C99 tutorial, or an
lcc-win32 tutorial. I don't see the point of discussing C99 constructs and
then how lcc-win implements them, if the reader is sitting at a C89
compiler.

It also changes the situation. If a cast is part of the syntax for assigning
literal structures, then obviously it modifies whatever you migth want to
say about "C casts".
 
J

jacob navia

Eric said:
jacob said:
[...]
A cast can be useful to avoid unnecessary operations. For instance,
given the declarations:

double double_value;
int integer_value;

If you write

integer_value /= double_value;

The integer is promoted to double to do the division, then the result
is converted to integer again. With a cast however, the unnecessary
promotions can be avoided:

integer_value /= (int)double_value;

It would be worth mentioning that the modified expression
may produce a different value than the original. For example,
consider integer_value=10 and double_value=3.5, where the
original code calculates 2 and the revised code calculates 3.
(Even better: consider double_value=0.1 ...)

Thanks. That is a very bad example as I see.

Better use += as in
integer_value += (int)double_value;

Thanks for that.

You can use a cast expression in another context, to indicate the type
of a composite constant literal. For instance:
typedef struct tagPerson {
char Name[75];
int age;
} Person;

void process(Person *);
...
process(&(Person){“Mary Smith” , 38});

This is not a cast, so it doesn't belong in a tutorial
about casts. (Except, perhaps, to explain that it is not
a cast despite a faint and superficial syntactic resemblance.)

You are right again.
The standard says in a footnote

Note that this differs from a cast expression.
For example, a cast specifies a conversion to scalar types
or void only, and the result of a cast expression is not an lvalue.

I had not even seen that. Thanks

jacob
 
R

Richard Heathfield

jacob navia said:

Casts
A cast expression is the transformation of an object from one type to
another.

No, it isn't. It is the transformation of a *value* from one type to
another.

For instance in:
void *p;
...
(char *)p;

I can't think of a single good reason for casting a void * to a char *.
When to use casts

A cast can be useful to avoid unnecessary operations. For instance,
given the declarations:

double double_value;
int integer_value;

If you write

integer_value /= double_value;

The integer is promoted to double to do the division, then the result
is converted to integer again. With a cast however, the unnecessary
promotions can be avoided:

integer_value /= (int)double_value;

....at the cost of a conversion to int, so the saving isn't as great as
you are leading the reader to believe.

<snipped: a point that Eric has already discussed elsethread>

You've completely failed to mention the (admittedly very few) places
where casts are actually a good idea.

When not to use casts

Casts, as any other of the constructs above, can be misused. In
general, they make almost impossible to follow the type hierarchy
automatically. C is weakly typed, and most of the ?weakness? comes
from casts expressions.

You might want to get a proofreader onto that paragraph.
 
K

Keith Thompson

jacob navia said:
I am still writing my tutorial book about C. Here is the section
about casts. I would be interested in your opinions about this. Some
people
have definite views about this subject ("never use casts") some others
(like me) are more "liberal" in this subject. I would be interested
in any feedback.

jacob

Why do you use the word "transformation" when the word "conversion"
already exists and is in common use?

It's not correct to say that a cast *is* a conversion (or
tranformation); rather, a cast *specifies* a conversion. Conversions
can occur without the use of a cast.

The operand of a cast is an expression, not necessarily an object.
For instance, a common need is to transform double precision
numbers into integers. This is specified like this:
double d;
...
(int)d
In this case, the cast needs to invoke run time code to make the
actual transformation. In other cases there is no code emitted at
all. For instance in:
void *p;
...
(char *)p;
Transforming one type of pointer into another needs no code at all at
run-time in most implementations.

When to use casts

A cast can be useful to avoid unnecessary operations. For instance,
given the declarations:

double double_value;
int integer_value;

If you write

integer_value /= double_value;

The integer is promoted to double to do the division, then the result
is converted to integer again. With a cast however, the unnecessary
promotions can be avoided:

integer_value /= (int)double_value;

Saying that the operation is "unnecessary" implies that this is just a
matter of performance. In fact, depending on the values of
double_value and integer_value, the cast can cause the expression to
yield a different result. It's a matter of correctness, and depending
on the requirements, adding the cast might break correct code.
You can use a cast expression in another context, to indicate the type
of a composite constant literal. For instance:
typedef struct tagPerson {
char Name[75];
int age;
} Person;

void process(Person *);
...
process(&(Person){“Mary Smith” , 38});

Your quotation marks are showing up as "\223" and "\224". Use
ordinary ASCII quotation marks, not whatever (Windows-specific?)
characters you're using here.
This is one of the new features of C99. The literal should be enclosed
in braces, and it should match the expected structure. This is just
“syntactic sugar” for the following:

Person __998815544ss = { “Mary Smith”, 38};
process(&__998815544ss);

That's not a cast, it's a compound literal, a separate kind of
expression. (For it to be a cast expression, the operand would have
to be an expression; the stuff enclosed in braces is not by itself a
valid expression.) The syntactic coincidence that it happens to
include a type name in parentheses doesn't make it a cast, any more
than sizeof(int) is a cast.
The advantage is that now you are spared that task of figuring out a
name for the structure since the compiler does that for
you. Internally however, that code represents exactly what happens
inside lcc-win32.

Is this tutorial going to be specific to lcc-win32?
When not to use casts

Casts, as any other of the constructs above, can be misused. In
general, they make almost impossible to follow the type hierarchy
automatically. C is weakly typed, and most of the “weakness”
comes from casts expressions.

That's now how I'd put it; I might comment further after I've had time
to think about it.

Briefly, though, the real problem with casts is that they often carry
an implicit message to the compiler of "I know what I'm doing, don't
bother me with warnings". Very often, this isn't the case, and the
result is errors that aren't diagnosed by the compiler.

You don't mention another case where casts are appropriate: coercing
an argument to a variadic function (such as printf) to the required
type. For non-variadic functions, if you have a prototype in scope,
this coercion will usually be done automatically. For variadic
functions, the compiler lacks enough information to determine the
proper type, so it's up to the programmer.
 
J

jacob navia

Keith said:
Why do you use the word "transformation" when the word "conversion"
already exists and is in common use?

Looked like synonyms to me. Granted, I changed that.
It's not correct to say that a cast *is* a conversion (or
tranformation); rather, a cast *specifies* a conversion. Conversions
can occur without the use of a cast.

The operand of a cast is an expression, not necessarily an object.

All expressions return a result object... and that object is converted.
Conversions can only act in objects whose values are converted
isn't it?

Or are we getting into philosophy??? :)

[snip]
Briefly, though, the real problem with casts is that they often carry
an implicit message to the compiler of "I know what I'm doing, don't
bother me with warnings". Very often, this isn't the case, and the
result is errors that aren't diagnosed by the compiler.

You don't mention another case where casts are appropriate: coercing
an argument to a variadic function (such as printf) to the required
type. For non-variadic functions, if you have a prototype in scope,
this coercion will usually be done automatically. For variadic
functions, the compiler lacks enough information to determine the
proper type, so it's up to the programmer.

You are right.

I added:

Another case when casts are necessary occurs when passing arguments to a
variadic function. Since the type of the arguments can’t be known by the
compiler, it is necessary to cast a value to its exact expected type
(double to float for example), so that the arguments are converted to
the exact types the variadic function expects.

For instance

float f;

printf("%Lg\n",(long double)f);

The printf function expects a long double (format Lg). We need to
convert our float f into a long double to match the expectations of
printf.
 
J

jacob navia

Richard said:
jacob navia said:


I still can't think of a single *good* reason for casting a void * to a
char *.

And why the above is not a good reason?

You would write:

char *cp = p;
int c = *cp;

Or how would you do that?
 
R

Richard Tobin

If you want to dereference it as a char *, maybe.

If I want to do that, I'll do this first:

char *p = vp;

Temps are cheap, and easy to read.[/QUOTE]


As usual, readability is in the eye of the beholder. Using a
temporary variable will use up vertical space, which I generally find
reduces readability (because it reduces what fits on a page). In this
case, I think *(char *)vp is a simple and common enough idiom that
it's not worth the extra space.

-- Richard
 
R

Richard Heathfield

Guillaume said:
If you want to dereference it as a char *, maybe.

If I want to do that, I'll do this first:

char *p = vp;

Temps are cheap, and easy to read.
 
R

Richard Heathfield

jacob navia said:
Keith Thompson wrote:


All expressions return a result object...

Expressions don't return anything. My C89 draft does occasionally
mention operators returning values, and functions can certainly return
values, but expressions don't return anything. They do, however, *have*
a value.

<snip>
 
J

jacob navia

Richard said:
If I want to do that, I'll do this first:

char *p = vp;

Temps are cheap, and easy to read.

No they are not.

If the declaration of the temp is 76 lines before
you have to look it up, then come back to see why you use
a temporary variable, then discover that is not used anywhere else
and that temp is just a variable to avoid a cast.

Writing a smaller piece of code like

int c = *((char *)p);

is immediately clear what you are doing.
 
J

jacob navia

Richard said:
jacob navia said:


Because it's difficult to read, for one thing. Because it can be unsafe,
for another. Because it's pointless, for a third.


If p points to a properly aligned int, I'd do this:

int *ip = p;

and then I'd use *ip, or define an int and assign *ip to it.
Note that my conversion was different:
int c = *((char *)p);

i.e. I am reading a byte from the void *;

But in matters of taste there is no absolute rules.

I will mention your viewpoint in the tutorial.
 
R

Richard Heathfield

jacob navia said:
And why the above is not a good reason?

Because it's difficult to read, for one thing. Because it can be unsafe,
for another. Because it's pointless, for a third.
You would write:

char *cp = p;
int c = *cp;

Or how would you do that?

If p points to a properly aligned int, I'd do this:

int *ip = p;

and then I'd use *ip, or define an int and assign *ip to it.
 
J

jacob navia

Richard said:
If I want to do that, I'll do this first:

char *p = vp;

Temps are cheap, and easy to read.


As usual, readability is in the eye of the beholder. [/QUOTE]

Yes. I will mention Mr Heathfield viewpoint in the tutorial.
I do not agree though.
Using a
temporary variable will use up vertical space, which I generally find
reduces readability (because it reduces what fits on a page). In this
case, I think *(char *)vp is a simple and common enough idiom that
it's not worth the extra space.

absolutely correct
 
G

Guillaume

jacob said:
A cast can be useful to avoid unnecessary operations.

Introducing casts, in a C tutorial, as an optimization technique seems
quite bizarre to me.
Talking about optimization in any introductory material is a very bad
idea IMO. "Premature optimization is the root of all evil." At best, it
is just distracting the novice from mastering the basics.

That said, it is doubtful that your claim be valid on most modern
platforms. It may even be misleading, and again IMO, it would be a bad
introduction on optimization as well.

Unfortunately, your example with a cast was not even a correct
equivalent of the original statement, as others have pointed out.

Casts should be used to insure correctness of expressions in respect to
the intended result - not to compromise it.
 
J

jacob navia

Guillaume said:
Introducing casts, in a C tutorial, as an optimization technique seems
quite bizarre to me.
Talking about optimization in any introductory material is a very bad
idea IMO. "Premature optimization is the root of all evil." At best, it
is just distracting the novice from mastering the basics.

That said, it is doubtful that your claim be valid on most modern
platforms. It may even be misleading, and again IMO, it would be a bad
introduction on optimization as well.

Unfortunately, your example with a cast was not even a correct
equivalent of the original statement, as others have pointed out.

Casts should be used to insure correctness of expressions in respect to
the intended result - not to compromise it.

Yes, the example was wrong.

Maybe this speaks against casts, but they are part of the language
and I have to treat that part isn't it?

I am not promoting casts for optimizations, I just wanted some
example for a cast usage, and I did not find anything better. By
changing the /= to += I hope I fixed the example, even if it is
not a very good one.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

Pointer casts for OOP 2
function casts 27
Casts on lvalues 74
Union and pointer casts? 13
Better casts? 10
casts and pointers 0
cast musings 19
Casts for srand? (FAQ 13.17) 2

Members online

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top