473,396 Members | 1,804 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,396 software developers and data experts.

Better casts?

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. 8) 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?

Jan 21 '06 #1
10 1688
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

Jan 21 '06 #2
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. 8) 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

Jan 21 '06 #3
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
Jan 21 '06 #4
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. 8) 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.
Jan 21 '06 #5
"Ralf" <ra**@hollyfamily.de> 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) ks***@mib.org <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.
Jan 21 '06 #6
In article <35************@news.flash-gordon.me.uk>,
Flash Gordon <sp**@flash-gordon.me.uk> 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?
Jan 22 '06 #7
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
Jan 22 '06 #8
Christian Bau <ch***********@cbau.freeserve.co.uk> writes:
In article <35************@news.flash-gordon.me.uk>,
Flash Gordon <sp**@flash-gordon.me.uk> 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) ks***@mib.org <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.
Jan 22 '06 #9
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
Jan 23 '06 #10
On 21 Jan 2006 06:25:42 -0800, "Ralf" <ra**@hollyfamily.de> 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


3. Casts which hide a programmer error.

--
Al Balmer
Sun City, AZ
Jan 23 '06 #11

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

26
by: Steven T. Hatton | last post by:
The code shown below is an example from the Coin3D documentation. I believe the use of the C-style cast is safe under the circumstances, but from what I've been exposed to (TC++PL(SE)), I would...
133
by: Gaurav | last post by:
http://www.sys-con.com/story/print.cfm?storyid=45250 Any comments? Thanks Gaurav
3
by: Howard | last post by:
Hi, I am maintaining a lot of code that is rife with C-style casts. I've seen a lot of comments that one should not use C-style casts at all. But I'm wondering what harm there could be in...
24
by: roberts.noah | last post by:
Where is it in the standard that C style casts are labeled depricated? I read that on a lot of websites but I can't find it in the standard. I have BS ISO/IEC 14882:2003 (2nd ed) as published by...
28
by: charlie | last post by:
Hi, I found an article on informit.com that talks about C++ casts http://www.informit.com/guides/content.asp?g=cplusplus&seqNum=285&rl=1 The strange thing is the author says the following...
13
by: dpbsmith.janissary.2006 | last post by:
I know C++ mostly from "learning by doing." My main reference is Stoustrup's book. I was puzzled by something in a colleague's code that looked like this: abc=BOOL(def) I asked him what that...
9
by: Vincent RICHOMME | last post by:
Is there any reason to use static_cast instead of old C syntax ? Let's say I declare GLfloat test = static_cast<GLfloat>(x); or GLfloat test = (GLfloat) x;
81
by: jacob navia | last post by:
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...
61
by: jacob navia | last post by:
Continuing the discussion about casts, I would like to know your opinions about the hairy subject of casts as lvalues, i.e. This will fail under lcc-win32, but MSVC and gcc will accept it. I...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.