Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Better casts?

Reply
Thread Tools

Better casts?

 
 
Ralf
Guest
Posts: n/a
 
      01-21-2006
Regarding numerical types, in my view, casts fall in one of two
categories:
1. Casts that change the value of an object
2. Casts that are actually redundant, but get rid of compiler/lint
warnings

As an example, consider this code:

unsigned int ui;
...
unsigned char uc = (unsigned char)ui;

Here, it is not clear from the code what the developer wanted to
achieve:
1. It is possible that ui exceeds the unsigned char range and the
programmer only wants to look at the lower (e. g. bits. Basically,
he wants to cut off significant bits and hence wants to change the
original value.
2. The developer knows that ui cannot hold values that exceed the
unsigned char range, so assigning ui to uc is safe and doesn't lose
bits (i. e. the original value is preserved). He only casts to shut up
the compiler/Lint.

Would it make sense to introduce cast macros that clearly indicate what
the programmer wants to do, as in:

#define VALUE_CAST(type, e) ( (type)(e) )
#define WARNING_CAST(type, e) ( (type)(e) )

In the code below the purpose of the cast would be self-explanatory:

unsigned char uc = WARNING_CAST(unsigned char, ui);

Maybe WARNING_CAST could be even augmented by an assert checking if the
source object is in the range of the target type.
Any comments?

 
Reply With Quote
 
 
 
 
Nick Keighley
Guest
Posts: n/a
 
      01-21-2006
Ralf wrote:
> Regarding numerical types, in my view, casts fall in one of two
> categories:
> 1. Casts that change the value of an object
> 2. Casts that are actually redundant, but get rid of compiler/lint
> warnings


couldn't you just get a better compiler?

<snip>

--
Nick Keighley

 
Reply With Quote
 
 
 
 
Vladimir S. Oka
Guest
Posts: n/a
 
      01-21-2006
Ralf wrote:

> Regarding numerical types, in my view, casts fall in one of
> two categories:
> 1. Casts that change the value of an object


These, I'd call bugs... Cast are decidedly not the language
constructs one should use to change the value of an object.

> 2. Casts that are actually redundant, but get rid of
> compiler/lint


These may not be redundant at all, e.g. where there's genuine
need to change the type of the object containing the value in
question.

> warnings
>
> As an example, consider this code:
>
> unsigned int ui;
> ...
> unsigned char uc = (unsigned char)ui;
>
> Here, it is not clear from the code what the developer wanted
> to achieve:
> 1. It is possible that ui exceeds the unsigned char range
> and the
> programmer only wants to look at the lower (e. g. bits.
> Basically, he wants to cut off significant bits and hence
> wants to change the original value.


No, the programmer does not really /want/ to change the value,
rather she's just hoping that the high order bits will all be
zero. It is entirely possible to check for that before casting.

> 2. The developer knows that ui cannot hold values that
> exceed the
> unsigned char range, so assigning ui to uc is safe and doesn't
> lose bits (i. e. the original value is preserved). He only
> casts to shut up the compiler/Lint.


He may actually cast because the design requires that the value
from this point on resides in an object of a different type.
Think hardware registers in an embedded design here.

>
> Would it make sense to introduce cast macros that clearly
> indicate what the programmer wants to do, as in:
>
> #define VALUE_CAST(type, e) ( (type)(e) )
> #define WARNING_CAST(type, e) ( (type)(e) )
>
> In the code below the purpose of the cast would be
> self-explanatory:
>
> unsigned char uc = WARNING_CAST(unsigned char, ui);


These are certainly possible, but I don't think they bring much
to the party...

>
> Maybe WARNING_CAST could be even augmented by an assert
> checking if the source object is in the range of the target
> type. Any comments?


And adding asserts to these would certainly be death by
defensive programming.

My tuppence, anyway...

Cheers

Vladimir

 
Reply With Quote
 
Vladimir S. Oka
Guest
Posts: n/a
 
      01-21-2006
Nick Keighley wrote:

> Ralf wrote:
>> Regarding numerical types, in my view, casts fall in one of
>> two categories:
>> 1. Casts that change the value of an object
>> 2. Casts that are actually redundant, but get rid of
>> compiler/lint
>> warnings

>
> couldn't you just get a better compiler?
>
> <snip>
>


A better programmer would be preferable...

Cheers

Vladimir
 
Reply With Quote
 
Flash Gordon
Guest
Posts: n/a
 
      01-21-2006
Vladimir S. Oka wrote:
> Ralf wrote:
>
>> Regarding numerical types, in my view, casts fall in one of
>> two categories:
>> 1. Casts that change the value of an object

>
> These, I'd call bugs... Cast are decidedly not the language
> constructs one should use to change the value of an object.


Not always the case, for example it can be the right thing to do with
the to* functions. Have a look at this thread for a discussion of the
issue
http://groups.google.co.uk/group/com...813857161a2020

>> 2. Casts that are actually redundant, but get rid of
>> compiler/lint

>
> These may not be redundant at all, e.g. where there's genuine
> need to change the type of the object containing the value in
> question.


True. For the OP, examples include printing a pointer using the %p
format specifier, where you need to convert the pointer to a void*
before passing it to printf.

>> warnings
>>
>> As an example, consider this code:
>>
>> unsigned int ui;
>> ...
>> unsigned char uc = (unsigned char)ui;
>>
>> Here, it is not clear from the code what the developer wanted
>> to achieve:
>> 1. It is possible that ui exceeds the unsigned char range
>> and the
>> programmer only wants to look at the lower (e. g. bits.
>> Basically, he wants to cut off significant bits and hence
>> wants to change the original value.

>
> No, the programmer does not really /want/ to change the value,
> rather she's just hoping that the high order bits will all be
> zero. It is entirely possible to check for that before casting.


How do you know what the programmer wants without asking the programmer?
There are legal well defined ways to use casts to change values,
although whether they are the method you or I would choose is another
matter.

>> 2. The developer knows that ui cannot hold values that
>> exceed the
>> unsigned char range, so assigning ui to uc is safe and doesn't
>> lose bits (i. e. the original value is preserved). He only
>> casts to shut up the compiler/Lint.

>
> He may actually cast because the design requires that the value
> from this point on resides in an object of a different type.
> Think hardware registers in an embedded design here.


A lot of the time such casts are not required.

>> Would it make sense to introduce cast macros that clearly
>> indicate what the programmer wants to do, as in:
>>
>> #define VALUE_CAST(type, e) ( (type)(e) )
>> #define WARNING_CAST(type, e) ( (type)(e) )
>>
>> In the code below the purpose of the cast would be
>> self-explanatory:
>>
>> unsigned char uc = WARNING_CAST(unsigned char, ui);

>
> These are certainly possible, but I don't think they bring much
> to the party...


Agreed. I definitely would not use such macros nor would I want them in
code I had to deal with. If it's not obvious why the cast is there (or
in any other instance where the purpose of the code is not clear) you
should use comments.

>> Maybe WARNING_CAST could be even augmented by an assert
>> checking if the source object is in the range of the target
>> type. Any comments?

>
> And adding asserts to these would certainly be death by
> defensive programming.
>
> My tuppence, anyway...


Added to which I would not add casts to code to shut up compiler warnings.
--
Flash Gordon
Living in interesting times.
Although my email address says spam, it is real and I read it.
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      01-21-2006
"Ralf" <> writes:
> Regarding numerical types, in my view, casts fall in one of two
> categories:
> 1. Casts that change the value of an object
> 2. Casts that are actually redundant, but get rid of compiler/lint
> warnings
>
> As an example, consider this code:
>
> unsigned int ui;
> ...
> unsigned char uc = (unsigned char)ui;


This is precisely equivalent to

unsigned int ui;
...
unsigned char uc = ui;

You could argue that the version with the cast is more explicit. On
the other hand, it has to repeat the target type, and it introduces
possibilities for error. For example, suppose you change the type of
the variable to unsigned short, but forget to change the cast.

*All* casts should be viewed with suspicion. There are a few cases
where they're necessary:

Passing an argument to a function that takes a variable number and
type of parameters. (You should always have a visible prototype
for any function you call; for ordinary functions, this will
impose an implicit conversion.)

Arithmetic conversions within expressions. For example:
int x = ...;
int y = ...;
long product = (long)x * (long)y;
Without the casts, the multiplication will be done in type int,
and the value converted to long afterwards. (Actually only one of
the casts is necessary, but I like the symmetry.) (And yes, I'm
assuming that long is wider than int.)

Pointer conversions in deliberately non-portable code.

Probably other cases I haven't thought of.

--
Keith Thompson (The_Other_Keith) kst- <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
 
Reply With Quote
 
Christian Bau
Guest
Posts: n/a
 
      01-22-2006
In article <>,
Flash Gordon <> wrote:

> How do you know what the programmer wants without asking the programmer?
> There are legal well defined ways to use casts to change values,
> although whether they are the method you or I would choose is another
> matter.


Example: I have a floating point value x which is known to be in the
range 0 <= x < 256. I want an unsigned char c with the value floor (x).

c = (unsigned char) x;

is a completely legal way to do this.

c = x;

is also a completely legal way to do this; however, it looks
suspiciously like a programming error.

/* This assignment is ok, we know that 0 <= x < 256 */
c = x;

is also completely legal, and it looks ok to me and you, but it might
not look ok to my compiler or your compiler.

c = floor (x);

is ok, but inefficient, it still looks like a programming error because
x might be outside the range 0 to 255.

c = (unsigned char) floor (x);

is ok, but inefficient, and what is the point of using floor () if you
cast the result to unsigned char immediately afterwards?
 
Reply With Quote
 
Vladimir S. Oka
Guest
Posts: n/a
 
      01-22-2006
Flash Gordon wrote:

> Vladimir S. Oka wrote:
>> Ralf wrote:
>>
>>> Regarding numerical types, in my view, casts fall in one of
>>> two categories:
>>> 1. Casts that change the value of an object

>>
>> These, I'd call bugs... Cast are decidedly not the language
>> constructs one should use to change the value of an object.

>
> Not always the case, for example it can be the right thing to
> do with the to* functions. Have a look at this thread for a
> discussion of the issue
>

http://groups.google.co.uk/group/com...813857161a2020
>


In that thread Richard said:

Richard Heathfield <compla...@eton.powernet.co.uk> wrote:
> Yes, it takes an int. But if you are going to cast it to
> anything, cast it to unsigned char.
> Why? Because if you give it anything that is neither EOF nor
> representable as an unsigned char, you invoke undefined
> behaviour. If you plan on passing
> EOF to toupper(), reconsider your design. Otherwise, cast to
> unsigned char if there is the slightest doubt that your data
> may not be representable as unsigned char. Rely on good
> testing procedures to pick up data errors. Or
> cut code to improve your validation.


I may not have made it clear in my post, by I was actually
trying to make his last point. Yes, you can use casts that
change the value to prevent UB or other problems, but
preferable route is to check your data explicitely.

>>> Basically, he wants to cut off significant bits and hence
>>> wants to change the original value.

>>
>> No, the programmer does not really /want/ to change the
>> value, rather she's just hoping that the high order bits will
>> all be zero. It is entirely possible to check for that before
>> casting.

>
> How do you know what the programmer wants without asking the
> programmer? There are legal well defined ways to use casts to
> change values, although whether they are the method you or I
> would choose is another matter.


You're right, we can't tell, and that's where I think the
problem lies. I'd certainly strongly discourage using casts to
change the value of an object: test, change value without
casting if needed, assign to a different type of object (with
or without explicit cast, depending on the case) would be my
preferable way.

I agree with the rest of what you said, hence the big snip
here...

Cheers

Vladimir
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      01-22-2006
Christian Bau <> writes:
> In article <>,
> Flash Gordon <> wrote:
>
>> How do you know what the programmer wants without asking the programmer?
>> There are legal well defined ways to use casts to change values,
>> although whether they are the method you or I would choose is another
>> matter.

>
> Example: I have a floating point value x which is known to be in the
> range 0 <= x < 256. I want an unsigned char c with the value floor (x).
>
> c = (unsigned char) x;
>
> is a completely legal way to do this.
>
> c = x;
>
> is also a completely legal way to do this; however, it looks
> suspiciously like a programming error.
>
> /* This assignment is ok, we know that 0 <= x < 256 */
> c = x;
>
> is also completely legal, and it looks ok to me and you, but it might
> not look ok to my compiler or your compiler.

[...]

A compiler might give you a warning about this, since it could invoke
undefined behavior of x is outside the range of unsigned char. But a
compiler could as easily give you a warning about the cast -- or about
that ugly tie you're wearing. Once it issues the warning, it *must*
compile the code correctly.

If you're adding a cast for the sole purpose of inhibiting a compiler
warning, you're probably doing something wrong. The classic example
is casting the result of malloc() rather than adding a
"#include <stdlib.h>". This isn't that bad, of course, but it is
potentially dangerous. Consider what happens if you change the type
of c (to signed char, or unsigned short, or whatever) and forget to
change the cast.

--
Keith Thompson (The_Other_Keith) kst- <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
 
Reply With Quote
 
Thad Smith
Guest
Posts: n/a
 
      01-23-2006
Keith Thompson wrote:

> If you're adding a cast for the sole purpose of inhibiting a compiler
> warning, you're probably doing something wrong.


That depends, of course, on the warning. I grant that casts can be
abused, but I see no problem with adding a cast to suppress a warning
that a value may lose precision on assigning an int to a unsigned char,
for example, when I know that the value is within range of the
assignment variable. That was the point of the warning cast mentioned
by the OP, I believe.

I prefer to suppress a warning that I investigated so that subsequent
compiler summaries aren't cluttered with warnings I have already checked.

--
Thad
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
GL2 better than the XLs? Consumer grade HDs better than pro-sumer Mini DVs? dh@. DVD Video 1 08-28-2008 07:20 PM
The SCO case gets better and better.... thingy NZ Computing 2 12-10-2006 11:33 AM
Is splint really better than lint? Is there a better tool than splint? Peter Bencsik C Programming 2 09-21-2006 10:02 PM
Build a Better Blair (like Build a Better Bush, only better) Kenny Computer Support 0 05-06-2005 04:50 AM
Why doesn't the better camera have a better dpi? Tony Carlisle Digital Photography 6 10-04-2003 10:40 AM



Advertisments