473,396 Members | 1,722 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.

two meanings of a cast

I haven't been thinking about it for years but recently I've stumbled on
the fact that 'casting' is actually doing (at least) two different
things:

On the one hand 'casting' means: 'Change something into somthing
else'. Example: double d=9.99; long l=(double)d;

On the other hand 'casting' means: 'Treating something as something
else without change'. For instance when casting function pointers.

Would You agree?

IMO this difference between 'conversion' and 'treatment' isn't probably
pointed out enough to C newcomers and may be one reason for the danger
of casts.

Felix
Apr 27 '07 #1
18 2176
Felix Kater wrote:
I haven't been thinking about it for years but recently I've stumbled on
the fact that 'casting' is actually doing (at least) two different
things:

On the one hand 'casting' means: 'Change something into somthing
else'. Example: double d=9.99; long l=(double)d;

On the other hand 'casting' means: 'Treating something as something
else without change'. For instance when casting function pointers.

Would You agree?
No.

In a cast expression `(T) E`, we're requiring the value of the expression
`E` to be converted to type `T` using the appropriate conversion machinery.

That's true everywhere.

Sometimes, the "appropriate conversion machinery" leaves the underlying
bit-pattern unchanged, leading to the illusion that the cast means "Treat
something as something else without change". But this is an accident of
implementation.

[We have seen in the past that conversion from say `char*` to `int*` and
back requires bit-fiddling code in some implementations.]
IMO this difference between 'conversion' and 'treatment' isn't probably
pointed out enough to C newcomers and may be one reason for the danger
of casts.
I don't think it's as simple as that. I suspect the danger comes from
casts of pointers and a belief that if `p` points somewhere sane then
the pointer `(T*) p` points somewhere equally sane and is dereferencable
to get values of type `T`.

--
Nit-picking is best done among friends.

Hewlett-Packard Limited Cain Road, Bracknell, registered no:
registered office: Berks RG12 1HN 690597 England

Apr 27 '07 #2
>>>>"FK" == Felix Kater <fk****@googlemail.comwrites:

FKOn the one hand 'casting' means: 'Change something into
FKsomthing else'. Example: double d=9.99; long l=(double)d;

FKOn the other hand 'casting' means: 'Treating something as
FKsomething else without change'. For instance when casting
FKfunction pointers.

FKWould You agree?

No; in your first case, you're also "treating something as something
else without change." The value of d does not change when you cast it
to a double (completely unnecessary, since that's what it is) and
assign it to l.

Charlton

--
Charlton Wilbur
cw*****@chromatico.net
Apr 27 '07 #3
On Apr 27, 1:23 pm, Chris Dollin <chris.dol...@hp.comwrote:

<snip>
Sometimes, the "appropriate conversion machinery" leaves the underlying
bit-pattern unchanged, leading to the illusion that the cast means "Treat
something as something else without change". But this is an accident of
implementation.
<snip>

Are you saying here that there exists an implementation that would
alter the bit pattern of an object as it is cast [keeping the
original's size constant] - or that the change in bits would likely be
the result of changing the size of the original?

Apr 27 '07 #4
Felix Kater wrote:
I haven't been thinking about it for years but recently I've stumbled on
the fact that 'casting' is actually doing (at least) two different
things:

On the one hand 'casting' means: 'Change something into somthing
else'. Example: double d=9.99; long l=(double)d;
That's fine, although it's a silly cast. `d' is already
a `double', so "converting" it to a `double' is unnecessary.
(The `double' result, whether "converted" or not, will then
be converted to `long' for initializing `l'.)
On the other hand 'casting' means: 'Treating something as something
else without change'. For instance when casting function pointers.

Would You agree?
No. A cast is an operator that performs a conversion (even
if the conversion is vacuous, as above). There is no such thing
as a "let's pretend" cast.

However, casts can convert a pointer of one type into a pointer
to another type, and there is something like a "let's pretend"
effect if the converted result is then used to access a pointed-
to object or function:

int i = 42;
unsigned char *p = (unsigned char*) &i;
printf ("The individual bytes of %d are:", i);
while (p < (unsigned char*)(&i + 1))
printf (" %d", *p++);
printf ("\n");

Line two takes the pointer-to-int value `&i' and converts
it to a pointer-to-unsigned-char, which it then stores in `p'.
There is no "let's pretend" at all: A value is converted from one
type to another, and that's that.

There's another such conversion on line four, where another
pointer-to-int is converted to pointer-to-unsigned-char for
purposes of comparison. Again, there's no "let's pretend:" the
cast converts the value `(&i + 1)' to a different type.

The "let's pretend" occurs on line five, where a pointer
to one type (unsigned char) is used to manipulate an object of
a different type (int). Observe that there is no cast in line
five: We are "treating something as something else without
change" by accessing it with different kinds of pointers, not
by applying a cast to it. (No cast is ever applied to `i'.)
IMO this difference between 'conversion' and 'treatment' isn't probably
pointed out enough to C newcomers and may be one reason for the danger
of casts.
It would be a disservice to newcomers to point out a difference
that doesn't exist. For the same reason, most introductory texts
omit mentioning the temperatures of C's data types.

--
Eric Sosman
es*****@acm-dot-org.invalid
Apr 27 '07 #5
On Fri, 27 Apr 2007 13:23:31 +0100
Chris Dollin <ch**********@hp.comwrote:
Sometimes, the "appropriate conversion machinery" leaves the
underlying bit-pattern unchanged, leading to the illusion that the
cast means "Treat something as something else without change". But
this is an accident of implementation.
Some notes:

'sometimes': This is exactly what I mean--from a students view. Talking
about casts does not give you the clue if data is converted or not.

'illusion': In practice it *is* a big difference if you can or cannot
cast something into somthing else and back again without having changed
a single byte. So calling it an illusion wouldn't help.

'accident of implementation': I wonder if there aren't cases in which
legal casts could simply never be 'conversions' nor make sense
as such in any implementation. So, this was reason why casts are ment
not to be conversions sometimes.

Felix
Apr 27 '07 #6
On Fri, 27 Apr 2007 08:58:24 -0400
Eric Sosman <es*****@acm-dot-org.invalidwrote:
Example: double d=9.99; long l=(double)d;

'd' is already a `double', so "converting" it to a `double' is
unnecessary.
True, that was a silly mistake: I meant:
Example: double d=9.99; long l=(long)d;

Felix
Apr 27 '07 #7
"pemo" <pe*********@gmail.comha scritto nel messaggio
news:11**********************@c18g2000prb.googlegr oups.com...
Are you saying here that there exists an implementation that would
alter the bit pattern of an object as it is cast [keeping the
original's size constant] - or that the change in bits would likely be
the result of changing the size of the original?
If sizeof(int) equals sizeof(float), do you expect

int i = SOME_INTEGER_CONSTANT;
float f = (float)i;

!memcmp(&i, &f, sizeof i)

to always be true, on *any* implementation?
Apr 27 '07 #8
pemo wrote:
On Apr 27, 1:23 pm, Chris Dollin <chris.dol...@hp.comwrote:
>Sometimes, the "appropriate conversion machinery" leaves the underlying
bit-pattern unchanged, leading to the illusion that the cast means "Treat
something as something else without change". But this is an accident of
implementation.

Are you saying here that there exists an implementation that would
alter the bit pattern of an object as it is cast [keeping the
original's size constant] - or that the change in bits would likely be
the result of changing the size of the original?
No, I'm saying that sometimes the conversion doesn't alter the bitpattern,
so looking at the bitpattern gives the illusion that the cast doesn't
really do anything.

(EG one could play with `unsigned char *` to discover the values of the
bytes and that the bytes of the converted value were equal to the bytes
of the original value; or one could read the assembler output of a
I-can-do-assembler-output compiler.)

This will happen with eg casting ints to longs and vice-versa on machines
where they're the same size, and often happens with casting between
object pointer values.

--
"Who do you serve, and who do you trust?" /Crusade/

Hewlett-Packard Limited registered no:
registered office: Cain Road, Bracknell, Berks RG12 1HN 690597 England

Apr 27 '07 #9
Felix Kater wrote:
On Fri, 27 Apr 2007 13:23:31 +0100
Chris Dollin <ch**********@hp.comwrote:
>Sometimes, the "appropriate conversion machinery" leaves the
underlying bit-pattern unchanged, leading to the illusion that the
cast means "Treat something as something else without change". But
this is an accident of implementation.

Some notes:

'sometimes': This is exactly what I mean--from a students view. Talking
about casts does not give you the clue if data is converted or not.
Excuse me, it does: the data is /always/ converted.

Sometimes the implementation of the conversion is trivial and preserves
the bit-pattern. Doesn't matter: the value has been converted.
'illusion': In practice it *is* a big difference if you can or cannot
cast something into somthing else and back again without having changed
a single byte.
Some conversions are lossless; some are not. Just because /sometimes/
the implementation doesn't have to do anything doesn't mean it always
won't.

If you stick to what the Standard guarantees, you won't write code
where your round-tripping is surprising.

I'd like examples of your "In practice it *is* a big difference".
So calling it an illusion wouldn't help.

'accident of implementation': I wonder if there aren't cases in which
legal casts could simply never be 'conversions' nor make sense
as such in any implementation. So, this was reason why casts are ment
not to be conversions sometimes.
It's not the reason, because they're not sometimes-not-conversions.

--
"Possibly you're not recalling some of his previous plans." Zoe, /Firefly/

Hewlett-Packard Limited Cain Road, Bracknell, registered no:
registered office: Berks RG12 1HN 690597 England

Apr 27 '07 #10
Felix Kater wrote:
On Fri, 27 Apr 2007 13:23:31 +0100
Chris Dollin <ch**********@hp.comwrote:
>Sometimes, the "appropriate conversion machinery" leaves the
underlying bit-pattern unchanged, leading to the illusion that the
cast means "Treat something as something else without change". But
this is an accident of implementation.

Some notes:

'sometimes': This is exactly what I mean--from a students view. Talking
about casts does not give you the clue if data is converted or not.
Yes, it does: A cast always, as in always, converts its
operand. Sometimes the conversion is vacuous, as in the
example you posted earlier of applying `(double)' to a `double'
value. It is a conversion nonetheless, just as `+' adds two
numbers even when one of them is zero. (Note that the bits
of the result of a vacuous cast need not agree with the bits
of the operand value: for example, double-to-double might
deliver the normalized equivalent of an unnormalized operand
on machines that support unnormalized floating-point.)

A cast is a unary operator, like unary `-' or unary `&'.
It delivers a result derived from its single operand; that
result may have a different type, and the conversion to a new
type may also produce a different value. The operand itself
is "read-only," and is never[*] changed by the cast.
[*] Well, if the operand is a `volatile' object, its value
may change as a result of being read. But that's not an effect
of the cast; it's the volatility that's at work.
'illusion': In practice it *is* a big difference if you can or cannot
cast something into somthing else and back again without having changed
a single byte. So calling it an illusion wouldn't help.
Some conversions are guaranteed to be reversible, some
are not. Some are guaranteed to be reversible only under
restricted circumstances (e.g., a `double' can be converted
to an `int' and then back again unchanged only if it's in a
suitable range and has no fractional part). Some are not
permitted at all. What's the big deal?
'accident of implementation': I wonder if there aren't cases in which
legal casts could simply never be 'conversions' nor make sense
as such in any implementation. So, this was reason why casts are ment
not to be conversions sometimes.
A cast is always a conversion, even if it merely converts
an operand's value to the operand's own type.

--
Eric Sosman
es*****@acm-dot-org.invalid
Apr 27 '07 #11
On Fri, 27 Apr 2007 08:58:24 -0400, Eric Sosman
> int i = 42;
unsigned char *p = (unsigned char*) &i;
printf ("The individual bytes of %d are:", i);
while (p < (unsigned char*)(&i + 1))
printf (" %d", *p++);
printf ("\n");
(for me the above should print what is in *(int*)(p+1))
i don't like to talk but is it not better
printf (" %d", (int) *p++);
?
--
la complessita' si puo' solo scalare
Apr 27 '07 #12
Ĵa\/b wrote On 04/27/07 15:27,:
On Fri, 27 Apr 2007 08:58:24 -0400, Eric Sosman
>> int i = 42;
unsigned char *p = (unsigned char*) &i;
printf ("The individual bytes of %d are:", i);
while (p < (unsigned char*)(&i + 1))
printf (" %d", *p++);
printf ("\n");
(for me the above should print what is in *(int*)(p+1))
No, not at all. Are you sure what you wrote is
what you meant?
i don't like to talk but is it not better
printf (" %d", (int) *p++);
?
Yes, that would be slightly better. On most machines,
`unsigned char' promotes to `int', but on "exotic" machines
it could promote to `unsigned char'. (Such a machine would
have UCHAR_MAX INT_MAX, hence sizeof(int)==1 and a `char'
at least sixteen bits wide. I'm told such machines exist.)
If it promotes to `unsigned int', then "%d" is the wrong
conversion specifier; "%d" is for plain `int'.

Still better would be

printf(" %u", (unsigned int) *p++);

... because it works correctly even when `p' points to
a value that is too large for an `int'. That's not a
problem in my example, but not all numbers are forty-two!

--
Er*********@sun.com
Apr 27 '07 #13
On Fri, 27 Apr 2007 15:51:28 -0400, Eric Sosman wrote:
>Ĵa\/b wrote On 04/27/07 15:27,:
>On Fri, 27 Apr 2007 08:58:24 -0400, Eric Sosman
>>> int i = 42;
unsigned char *p = (unsigned char*) &i;
printf ("The individual bytes of %d are:", i);
while (p < (unsigned char*)(&i + 1))
printf (" %d", *p++);
printf ("\n");

(for me the above should print what is in *(int*)(p+1))

No, not at all. Are you sure what you wrote is
what you meant?
in the time i were sure now not;
it seems the compiler here cast the argument of printf
to int first than to call printf. is that behaviour for every function
or just for printf? is this behaviour just for chars or is for all
types?
>i don't like to talk but is it not better
printf (" %d", (int) *p++);
?

Yes, that would be slightly better. On most machines,
`unsigned char' promotes to `int', but on "exotic" machines
it could promote to `unsigned char'. (Such a machine would
in a machine like above should be
sizeof(void*)<=sizeof(unsigned char)
in the other case how is it possible "to printf" a pointer
if sizeof(char*)sizeof(unsigned char) and cast the pointer
with (unsigned char)
>have UCHAR_MAX INT_MAX, hence sizeof(int)==1 and a `char'
at least sixteen bits wide. I'm told such machines exist.)
If it promotes to `unsigned int', then "%d" is the wrong
conversion specifier; "%d" is for plain `int'.

Still better would be

printf(" %u", (unsigned int) *p++);

... because it works correctly even when `p' points to
a value that is too large for an `int'. That's not a
problem in my example, but not all numbers are forty-two!
this is more than i can understand
Apr 28 '07 #14
Ĵa\/b wrote:
On Fri, 27 Apr 2007 15:51:28 -0400, Eric Sosman wrote:
>Ĵa\/b wrote On 04/27/07 15:27,:
>>On Fri, 27 Apr 2007 08:58:24 -0400, Eric Sosman

int i = 42;
unsigned char *p = (unsigned char*) &i;
printf ("The individual bytes of %d are:", i);
while (p < (unsigned char*)(&i + 1))
printf (" %d", *p++);
printf ("\n");
(for me the above should print what is in *(int*)(p+1))
No, not at all. Are you sure what you wrote is
what you meant?

in the time i were sure now not;
it seems the compiler here cast the argument of printf
to int first than to call printf. is that behaviour for every function
or just for printf? is this behaviour just for chars or is for all
types?
When you pass an argument and the compiler does not know
the type of the corresponding parameter (that is, when you are
calling a function with no prototype or when you are passing
one of the "..." arguments to a variable-argument function),
the compiler "promotes" the argument by converting its value
to one of a standard set of types. For example, arguments of
type float are converted to double and passed to the function
as if you had provided double values to begin with.

"Narrow" integer types -- char, short, some others -- are
also promoted, but the promotion is a little bit tricky:

- If all possible values of the narrow type are within the
range of int, the value is promoted to an int and passed
as if you had provided an int argument.

- Otherwise, the value is promoted to an unsigned int and
passed as if you had provided an unsigned int argument.

So: *p is an unsigned char, which is a "narrow" integer
type. On most machines int has a wider range than char, so the
value of *p will be converted from char to int and passed to
printf() as an int. On a few unusual machines it is possible
that unsigned char can hold values that are numerically larger
than an int can hold, and on these machines *p will be converted
to unsigned int. (On these machines you will have sizeof(int)==1,
and since int is at least sixteen bits wide it follows that char
will be at least sixteen bits wide.)
>>i don't like to talk but is it not better
printf (" %d", (int) *p++);
?
Yes, that would be slightly better. On most machines,
`unsigned char' promotes to `int', but on "exotic" machines
it could promote to `unsigned char'. (Such a machine would

in a machine like above should be
sizeof(void*)<=sizeof(unsigned char)
Since sizeof(unsigned char) is 1, `=' is possible but
`<' is not.
in the other case how is it possible "to printf" a pointer
if sizeof(char*)sizeof(unsigned char) and cast the pointer
with (unsigned char)
I'm sorry: I do not understand your question.
>have UCHAR_MAX INT_MAX, hence sizeof(int)==1 and a `char'
at least sixteen bits wide. I'm told such machines exist.)
If it promotes to `unsigned int', then "%d" is the wrong
conversion specifier; "%d" is for plain `int'.

Still better would be

printf(" %u", (unsigned int) *p++);

... because it works correctly even when `p' points to
a value that is too large for an `int'. That's not a
problem in my example, but not all numbers are forty-two!

this is more than i can understand
As explained above, there is some ambiguity about the
type of the value printf() will receive when you provide an
unsigned char argument: On most machines the argument will be
converted to int, but on unusual machines it may be converted
to unsigned int. This line removes the ambiguity by casting
the value to unsigned int: now printf() will receive an unsigned
int on all machines, typical and unusual. But "%d" is not the
right conversion specifier for unsigned int; "%d" works with an
ordinary int or signed int value. Since the value in this case
will be an unsigned int, I use "%u" instead of "%d".

--
Eric Sosman
es*****@acm-dot-org.invalid
Apr 28 '07 #15
On Sat, 28 Apr 2007 14:58:59 -0400, Eric Sosman wrote:
thank you
Apr 29 '07 #16
On Apr 27, 11:33 pm, Felix Kater <fka...@googlemail.comwrote:
I haven't been thinking about it for years but recently I've stumbled on
the fact that 'casting' is actually doing (at least) two different
things:
A little off-topic here, but in C++ they introduced new syntax to
distinguish between three different 'sorts' of casting from C:
- static_cast is for conversions of values
- reinterpret_cast is for converting a pointer to be one that
points to a different type
- const_cast is for adding or removing const or volatile
qualifiers without changing anything else.

Apr 29 '07 #17

"Old Wolf" <ol*****@inspire.net.nzwrote in message
news:11**********************@o5g2000hsb.googlegro ups.com...
On Apr 27, 11:33 pm, Felix Kater <fka...@googlemail.comwrote:
>I haven't been thinking about it for years but recently I've stumbled on
the fact that 'casting' is actually doing (at least) two different
things:

A little off-topic here, but in C++ they introduced new syntax to
distinguish between three different 'sorts' of casting from C:
- static_cast is for conversions of values
- reinterpret_cast is for converting a pointer to be one that
points to a different type
- const_cast is for adding or removing const or volatile
qualifiers without changing anything else.
Good to know.
--
WW
Apr 30 '07 #18

"Chris Dollin" <ch**********@hp.comha scritto nel messaggio
news:f0**********@murdoch.hpl.hp.com...
No, I'm saying that sometimes the conversion doesn't alter the bitpattern,
so looking at the bitpattern gives the illusion that the cast doesn't
really do anything.

(EG one could play with `unsigned char *` to discover the values of the
bytes and that the bytes of the converted value were equal to the bytes
of the original value;
Or just use memcmp()...;
May 25 '07 #19

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

Similar topics

0
by: Aaron W. West | last post by:
Fun with CAST! (Optimized SQLServerCentral script posts) I found some interesting "tricks" to convert binary to hexadecimal and back, which allow doing 4 or 8 at a time. Test code first: --...
4
by: Ray | last post by:
When a single-bit bitfield that was formed from an enum is promoted/cast into an integer, does ANSI C say anything about whether that integer should be signed or unsigned? SGI IRIX cc thinks it is...
17
by: Hazz | last post by:
In this sample code of ownerdraw drawmode, why does the '(ComboBox) sender' line of code need to be there in this event handler? Isn't cboFont passed via the managed heap, not the stack, into this...
5
by: Nick Flandry | last post by:
I'm running into an Invalid Cast Exception on an ASP.NET application that runs fine in my development environment (Win2K server running IIS 5) and a test environment (also Win2K server running IIS...
5
by: zafar haider | last post by:
what are the specific meanings of word ".Net". what describes the word ".Net" why not something else please tell me the answer becuase it was asked in my interview
6
by: Lore Leunoeg | last post by:
Hello I derived a class MyControl from the Control class. Public Class MyControl Inherits Control Sub New() MyBase.New() End Sub End Class
9
by: Frederick Gotham | last post by:
Let's assume that we're working on the following system: CHAR_BIT == 8 sizeof( char* ) == 4 (i.e. 32-Bit) Furthermore, lets assume that the memory addresses are distributed as follows: ...
5
by: Frederick Gotham | last post by:
Before I begin, here's a list of assumptions for this particular example: (1) unsigned int has no padding bits, and therefore no invalid bit- patterns or trap representations. (2) All types have...
1
by: Tim Couper | last post by:
As you know, when an IOError is raised, you get a helpful: <useful descriptor of the error> Is there a list of all possible values of N which can be returned, and their meanings? -- Dr...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
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
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
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...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

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.