Richard heathfields casting operation

S

sophia.agnes

Hi ,

I was going through peter van der linden's book Expert C programming,
in this book there is a section named "How and why to cast"

the author then says as follows

(float) 3 - it's a type conversion and the actual bits change.
if you say (float) 3.0 it is a type disambiguation,and the compiler
can plant the correct bits in the first place.some people say that
casts are so named because they help something broken to limp along.

what exactly is this type disambiguation...????
i have n't seen any casts like (float) 3.0; in use (may be due to my
limited experience). how will it help the compiler to plant the
correct bits????

Then the author says that as an impratical example ,you can create a
pointer to ,for example printf(), with

extern int printf(const char*,...);
voif *f = (void *) printf;

you can then call printf through a properly cast pointer, in this
manner:

(*(int(*)(const char*,...))f)("Bite my shorts. Also my chars and ints
\n");

now void *f = (void *) printf; why this cast is required....????
^^^^^^
why the author says that above example is impractical...???
why is it because library functions are not meant to be called via
void pointer.....?????

for explanation of above issues i went to Richard heathfields site:
http://www.cpax.org.uk/prg/writings/casting.php

there i found nothing mentioned about type disambiguation..
but i found more complex example such as this

(int)((int (*)(const char *, ...))
printf((const char *)"%3.0f %6.1f\n",
(float)fahr, (float)celsius));

what exactly does this statement does...???

is it just simple printf such as this....
printf("%3.0f %6.1f\n",fahr, celsius);

why all these redundant casts such as

1)(const char *)"%3.0f %6.1f\n"
2)(int)((int (*)(const char *, ...))
 
C

Chris Dollin

I was going through peter van der linden's book Expert C programming,
in this book there is a section named "How and why to cast"

Then the author says that as an impratical example ,you can create a
pointer to ,for example printf(), with

extern int printf(const char*,...);
voif *f = (void *) printf;

That's not portable; there's no guarantee that a pointer-to-function
will fit in a pointer-to-void (and on some implementations, it
doesn't).
for explanation of above issues i went to Richard heathfields site:
http://www.cpax.org.uk/prg/writings/casting.php

there i found nothing mentioned about type disambiguation..
but i found more complex example such as this

(int)((int (*)(const char *, ...))
printf((const char *)"%3.0f %6.1f\n",
(float)fahr, (float)celsius));

what exactly does this statement does...???

The text of that page explains what's going on. Here's a quote:

Believe it or not, those casts are all "correct". And yes, the code
works just fine. But suddenly the code isn't quite as easy to read,
is it? So much for self-documentation.
 
R

Richard Heathfield

(e-mail address removed) said:
Hi ,

I was going through peter van der linden's book Expert C programming,
in this book there is a section named "How and why to cast"

the author then says as follows

(float) 3 - it's a type conversion and the actual bits change.
if you say (float) 3.0 it is a type disambiguation,and the compiler
can plant the correct bits in the first place.some people say that
casts are so named because they help something broken to limp along.

In my edition, it says (double) 3 and (double) 3.0 - he's right about the
conversion but wrong about the disambiguation, since 3.0 is of type
double, so casting it to double doesn't disambiguate anything, as there is
no ambiguity to disambiguate.
what exactly is this type disambiguation...????
Absent.

i have n't seen any casts like (float) 3.0; in use (may be due to my
limited experience). how will it help the compiler to plant the
correct bits????

If you need a float with the value 3.0f, just say 3.0f - there is no need
to cast.
Then the author says that as an impratical example ,you can create a
pointer to ,for example printf(), with

extern int printf(const char*,...);
voif *f = (void *) printf;

Whilst this is a common extension, the Standard does not guarantee that you
can store a function pointer in a void * without losing information.
Better to do this (in which case no cast is required):

int (*f)(const char *, ...) = printf;
you can then call printf through a properly cast pointer, in this
manner:

(*(int(*)(const char*,...))f)("Bite my shorts. Also my chars and ints
\n");

Not guaranteed as written. But with my suggested change, you don't need to
cast. You just do either (*f)("Bite...\n"); or even simply f("Bite...\n");
at your discretion.
now void *f = (void *) printf; why this cast is required....????
^^^^^^

The code is broken. Don't use it.
why the author says that above example is impractical...???

Perhaps because the code is broken.
why is it because library functions are not meant to be called via
void pointer.....?????

Because the Standard doesn't guarantee that it's possible.
for explanation of above issues i went to Richard heathfields site:
http://www.cpax.org.uk/prg/writings/casting.php

there i found nothing mentioned about type disambiguation..

Right. There's no need for it. Casting is not about disambiguation.
but i found more complex example such as this

(int)((int (*)(const char *, ...))
printf((const char *)"%3.0f %6.1f\n",
(float)fahr, (float)celsius));

what exactly does this statement does...???

It's a kind of picture. Some people claim that casts "clarify" code. This
picture takes them at their word. Which do you think is clearer - the
above, or printf("%3.0f %6.1f\n", fahr, celsius))? I know which one I'd
choose.

<snip>
 
P

Philip Potter

Richard said:
(e-mail address removed) said:


In my edition, it says (double) 3 and (double) 3.0 - he's right about the
conversion but wrong about the disambiguation, since 3.0 is of type
double, so casting it to double doesn't disambiguate anything, as there is
no ambiguity to disambiguate.


If you need a float with the value 3.0f, just say 3.0f - there is no need
to cast.


Whilst this is a common extension, the Standard does not guarantee that you
can store a function pointer in a void * without losing information.
Better to do this (in which case no cast is required):

int (*f)(const char *, ...) = printf;


Not guaranteed as written. But with my suggested change, you don't need to
cast. You just do either (*f)("Bite...\n"); or even simply f("Bite...\n");
at your discretion.


The code is broken. Don't use it.


Perhaps because the code is broken.


Because the Standard doesn't guarantee that it's possible.


Right. There's no need for it. Casting is not about disambiguation.


It's a kind of picture. Some people claim that casts "clarify" code. This
picture takes them at their word. Which do you think is clearer - the
above, or printf("%3.0f %6.1f\n", fahr, celsius))? I know which one I'd
choose.

Doesn't it call printf, cast the result to 'int (*)(const char *,...)',
then cast it again to 'int'? Shouldn't it therefore be:

(int)(
((int (*)(const char *, ...))printf)
((const char *)"%3.0f %6.1f\n",(float)fahr, (float)celsius)
);

If not, doesn't that mean that the (pointless) cast in the following:

int *x = (int *)malloc(sizeof *x); /* Don't do this. */

is actually casting malloc, not malloc's return value, to 'int *'?
 
S

sophia.agnes

(e-mail address removed) said:





In my edition, it says (double) 3 and (double) 3.0 - he's right about the
conversion but wrong about the disambiguation, since 3.0 is of type
double, so casting it to double doesn't disambiguate anything, as there is
no ambiguity to disambiguate.


If you need a float with the value 3.0f, just say 3.0f - there is no need
to cast.





Whilst this is a common extension, the Standard does not guarantee that you
can store a function pointer in a void * without losing information.
Better to do this (in which case no cast is required):

int (*f)(const char *, ...) = printf;





Not guaranteed as written. But with my suggested change, you don't need to
cast. You just do either (*f)("Bite...\n"); or even simply f("Bite...\n");
at your discretion.




The code is broken. Don't use it.


Perhaps because the code is broken.


Because the Standard doesn't guarantee that it's possible.



Right. There's no need for it. Casting is not about disambiguation.




It's a kind of picture. Some people claim that casts "clarify" code. This
picture takes them at their word. Which do you think is clearer - the
above, or printf("%3.0f %6.1f\n", fahr, celsius))? I know which one I'd
choose.

<snip>

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999

i compiled and executed your program:-

#include <stdio.h>
main()
{
float fahr, celsius;
int lower, upper, step;

lower = (int)0; /* lower limit of temperature table */
upper = (int)300; /* upper limit */
step = (int)20; /* step size */

fahr = (float)lower;
while((float)fahr <= (int)upper) {
celsius = (((float)
((float)5.0/(float)9.0)) *
(float)((float)
(((float)fahr-(float)32.0))));

(int)((int (*)(const char *, ...))
printf((const char *)"%3.0f %6.1f\n",
(float)fahr, (float)celsius));

fahr = (float)((float)fahr + (float)step);
}

gcc -o casting casting.c
../casting

i got the following result:-

0 -17.8
20 -6.7
40 4.4
60 15.6
80 26.7
100 37.8
120 48.9
140 60.0
160 71.1
180 82.2
200 93.3
220 104.4
240 115.6
260 126.7
280 137.8
300 148.9

I manually did the calculation for one value by using calculator
for your 220 104.4 values calculator o/p is
219.92 104.4
(calculation done for fahr value based on celsius value 104.4)
so your program is not accurate by a value of .08
 
P

Philip Potter

i compiled and executed your program:-
I manually did the calculation for one value by using calculator
for your 220 104.4 values calculator o/p is
219.92 104.4
(calculation done for fahr value based on celsius value 104.4)
so your program is not accurate by a value of .08

Perhaps you should look at your printf() documentation to understand
what this line does:
printf("%3.0f %6.1f\n",fahr, celsius);

Also, please trim the text you quote. It's in general better to quote
too much than too little, but you quoted an entire message to respond to
one point within it.

Phil
 
J

James Kuyper

i compiled and executed your program:-

#include <stdio.h>
main()
{
float fahr, celsius;
int lower, upper, step;

lower = (int)0; /* lower limit of temperature table */
upper = (int)300; /* upper limit */
step = (int)20; /* step size */

fahr = (float)lower;
while((float)fahr <= (int)upper) {
celsius = (((float)
((float)5.0/(float)9.0)) *
(float)((float)
(((float)fahr-(float)32.0))));

(int)((int (*)(const char *, ...))
printf((const char *)"%3.0f %6.1f\n",
(float)fahr, (float)celsius));

fahr = (float)((float)fahr + (float)step);
}

gcc -o casting casting.c
./casting

i got the following result:-

0 -17.8
20 -6.7
40 4.4
60 15.6
80 26.7
100 37.8
120 48.9
140 60.0
160 71.1
180 82.2
200 93.3
220 104.4
240 115.6
260 126.7
280 137.8
300 148.9

I manually did the calculation for one value by using calculator
for your 220 104.4 values calculator o/p is
219.92 104.4
(calculation done for fahr value based on celsius value 104.4)
so your program is not accurate by a value of .08

There's no error in his program (as far as I can tell). All you've done
is demonstrated that when floating point values are rounded (as in
general, they must be), they are no longer exact.

The exact value of the Celsius temperature corresponding to 220
Fahrenheit is 104 4/9 = 104.44444.... . Since 9 is not a power of 2,
this value cannot be stored exactly in typical floating point formats,
however in general it will be a very good approximation.

The "%6.1f" format code rounds that approximation to 1 digit after the
decimal place, giving 104.4, exactly as shown by his program. This value
is inaccurate by 4/9-4/10 = 4/90 = 0.044444444.... That is called
roundoff error, and it's a fact of life when doing floating point
calculations. You'll have to get used to it, and you should try to
understand it, otherwise you're likely to write code that produces
nonsense. It is that roundoff error which, when propagated backward,
gives you the 0.08 error in the Fahrenheit temperature.
 
R

Richard Heathfield

Philip Potter said:
Doesn't it call printf, cast the result to 'int (*)(const char *,...)',
then cast it again to 'int'?

Ouch! Yes, it does. Or at least, it did. I've now fixed the example.

That bug has survived unnoticed (or at least unreported) through 6,288 page
views, an average of around 7 per day over 28 months. Congratulations on
spotting it. And you just highlighted Yet Another Reason not to add
spurious casts.
 
S

Spoon

Richard said:
Whilst this is a common extension, the Standard does not
guarantee that you can store a function pointer in a void *
without losing information.

To emphasize your point, there are real platforms where casting
function pointers to void pointers will break.

(Linux/IA-64 is one such platform.)
 
P

Philip Potter

Richard said:
Philip Potter said:

Ouch! Yes, it does. Or at least, it did. I've now fixed the example.

That bug has survived unnoticed (or at least unreported) through 6,288 page
views, an average of around 7 per day over 28 months. Congratulations on
spotting it.

I feel most proud :)
And you just highlighted Yet Another Reason not to add
spurious casts.

Indeed.
 
K

Keith Thompson

Spoon said:
To emphasize your point, there are real platforms where casting
function pointers to void pointers will break.

I wouldn't be surprised.
(Linux/IA-64 is one such platform.)

Is it? void* and function pointers are both 8 bytes on Linux/IA-64.
I don't see any reason why it shouldn't work (unless the compiler
chooses to forbid it), and it works for me with at least one example:
========================================
% uname -a
Linux tg-login1 2.4.21-314.tg1 #1 SMP Tue Nov 21 15:49:16 CST 2006 ia64 unknown
% cat c.c
#include <stdio.h>

typedef int (*pointer_to_printf)(char *, ...);

int main(void)
{
void *p = printf;

printf("sizeof(void*) = %d\n", (int)sizeof(void*));
printf("sizeof(pointer_to_printf) = %d\n", (int)sizeof(pointer_to_printf));
((pointer_to_printf)p)("p = %p\n", p);
((pointer_to_printf)p)("printf = %p\n", (void*)printf);

return 0;
}
% ./c
sizeof(void*) = 8
sizeof(pointer_to_printf) = 8
p = 0x2000000000039608
printf = 0x2000000000039608
========================================

Of course this doesn't prove anything, but I'm curious why you think
that such conversions will break on Linux/IA-64.

(BTW, I don't know how much longer I'll have access to that system.)
 
D

Dik T. Winter

But was it a bug? Ah, yes, it is. The first conversion is allowed, but
is implementation defined, but the second conversion is not necessarily
allowed, because it can be undefined behavior.
>
> Indeed.

Morover, the original did show how easy it is to get complex casts right.
 
O

Old Wolf

(e-mail address removed) said:

If you need a float with the value 3.0f, just say 3.0f - there is no need
to cast.

Is 3.0f required to be equal to (float)3.0 ?
 
J

James Kuyper

Old Wolf wrote:
....
Is 3.0f required to be equal to (float)3.0 ?

The C standard is silent on the precision of floating point operations,
though it does acknowledge that they can be imprecise. On this basis, it
has been argued that even 3.0 is not required to compare equal to 3.0. I
think that's going to extremes, but the point it makes is valid. What
the C standard alone leaves unspecified about floating point operations
is sufficient to justify avoiding C for any serious numerical work.
Luckily, C is not the only applicable standard, and when other standards
also apply, C can be quite useful for such work..

The IEC 559 standard does contain lots of specifications about the
required precision of floating point operations, and those specification
are pretty tight, so when __STDC_IEC_559__ is defined, the conversion
of 3.0 from double to float is required to be exact, and the result
therefore must compare equal to 3.0F.
 
P

Peter 'Shaggy' Haywood

Groovy hepcat Dik T. Winter was jivin' in comp.lang.c on Thu, 8 Nov 2007
12:18 pm. It's a cool scene! Dig it.
But was it a bug? Ah, yes, it is. The first conversion is allowed,
but is implementation defined, but the second conversion is not
necessarily allowed, because it can be undefined behavior.

No, no. The cast to int (notwithstanding the other cast) was correct
(in the sense that it's allowed and doesn't cause undefined behaviour)
though pointless. The cast to int (*)(const char *, ...) (or whatever
it was) was incorrect because it applied to the return value instead of
the function itself. It should have been applied to the function by
enclosing the cast and function name in parentheses. That is, it should
have been this

(int (*)(const char *, ...)printf)("Whatever.");

as opposed to this

int (*)(const char *, ...)printf("Whatever.");

This cast is also pointless.
I spotted the error immediately, and am surprised Richard made such a
mistake. I was going to mention it, but then I saw Philip's post. I am
flabbergasted that this has remained unreported for so long. My gast
has never been so flabbered! :)
Morover, the original did show how easy it is to get complex casts
right.

No, it showed how easy it is to get casts wrong. Hence the statement
that Philip "highlighted Yet Another Reason not to add spurious casts."
 
P

Philip Potter

James said:
Old Wolf wrote:
...

The C standard is silent on the precision of floating point operations,
though it does acknowledge that they can be imprecise. On this basis, it
has been argued that even 3.0 is not required to compare equal to 3.0. I
think that's going to extremes, but the point it makes is valid. What
the C standard alone leaves unspecified about floating point operations
is sufficient to justify avoiding C for any serious numerical work.
Luckily, C is not the only applicable standard, and when other standards
also apply, C can be quite useful for such work..

However, 3.0 can always be represented exactly as a double or float:
base b >= 4: 3 x b^0
base b == 3: 1 x 3^1
base b == 2: 1.1 x 2^1
These are all guaranteed by the details in n1256 5.2.4.2.2.

Having said that, I can't find any detail which requires 3.0 to be
rounded correctly, but 6.4.4.2p2 states that 0x3.0 must be correctly
rounded for power-of-two bases. So 0x3.0 == 0x3.0 almost always but
AFAICS 3.0 may not necessarily equal 3.0...
 
J

James Kuyper

Philip said:
However, 3.0 can always be represented exactly as a double or float:
base b >= 4: 3 x b^0 base b == 3: 1 x 3^1 base b == 2: 1.1 x 2^1
These are all guaranteed by the details in n1256 5.2.4.2.2.

Yes. Any sufficiently small integer can be represented exactly as a
floating point number, no matter what the value of FLT_RADIX is.
However, that's not the critical issue.
Having said that, I can't find any detail which requires 3.0 to be
rounded correctly, but 6.4.4.2p2 states that 0x3.0 must be correctly
rounded for power-of-two bases. So 0x3.0 == 0x3.0 almost always but
AFAICS 3.0 may not necessarily equal 3.0...

I don't see anything in 6.4.4.2p2 that says that. Perhaps you were
thinking of the next paragraph? The relevant words from 6.4.4.2p3 say that:

| For decimal floating constants, and also for hexadecimal floating
| constants when FLT_RADIX is not a power of 2, the result is either
| the nearest representable value, or the larger or smaller
| representable value immediately adjacent to the nearest representable
| value, chosen in an implementation-defined manner.

This means that a conforming implementation could convert the literal
"3.0" into the next representable value either below or above the
exact representation of 3.0; and there's not even any requirement that
it make the same choice every time (so long as it documents the manner
in which it makes the choice). That's why 3.0 == 3.0 is not guaranteed
to be true. Arguably, the specification should have required the use of
the exact representation, if an exact representation exists, but I
suspect that it was felt necessary to accommodate some simple-but-fast
implementations that can't guarantee recognition of exact
representability in all cases. However, even the simplest of algorithms
shouldn't have a problem with small integers like 3.0.

6.4.4.2p3 is a relatively minor issue; the maximum error it allows is
very tiny. The dangerous clause is 5.2.4.2.2p5:

| The accuracy of the floating-point operations (+, -, *, /) and of the
| library functions in <math.h> and <complex.h> that return
| floating-point results is implementationdefined, as is the accuracy
| of the conversion between floating-point internal representations and
| string representations performed by the library functions in
| <stdio.h>, <stdlib.h>, and <wchar.h>. The implementation may state
| that the accuracy is unknown.

Do you realize that this means that a conforming implementation of C
could, for instance, declare in it's documentation that no floating
point operation is guaranteed to have a relative accuracy greater than
+/-50%, nor an absolute accuracy greater than +/-0.5? That's an extreme
case, but for serious numerical work there are real implementations
whose accuracy specification is almost as much of a nightmare.

That's why, if the only thing you know about a compiler's floating point
implementation is that it conforms to the C standard, it's unusable.
Only if you have additional information (for instance, that
__STDC_IEC_559__ is defined) can you even dare to use C floating point
numbers.
 
P

Philip Potter

James said:
Philip said:
>>> [is 3.0 == 3.0 guaranteed?]
Having said that, I can't find any detail which requires 3.0 to be
rounded correctly, but 6.4.4.2p2 states that 0x3.0 must be correctly
rounded for power-of-two bases. So 0x3.0 == 0x3.0 almost always but
AFAICS 3.0 may not necessarily equal 3.0...

I don't see anything in 6.4.4.2p2 that says that. Perhaps you were
thinking of the next paragraph? The relevant words from 6.4.4.2p3 say that:

Yes, you're right about the paragraph.
| For decimal floating constants, and also for hexadecimal floating
| constants when FLT_RADIX is not a power of 2, the result is either
| the nearest representable value, or the larger or smaller
| representable value immediately adjacent to the nearest representable
| value, chosen in an implementation-defined manner.

This means that a conforming implementation could convert the literal
"3.0" into the next representable value either below or above the
exact representation of 3.0; and there's not even any requirement that
it make the same choice every time (so long as it documents the manner
in which it makes the choice). That's why 3.0 == 3.0 is not guaranteed
to be true.

...but 0x3.0 == 0x3.0 *is* guaranteed under power-of-two radix, yes?
Arguably, the specification should have required the use of
the exact representation, if an exact representation exists, but I
suspect that it was felt necessary to accommodate some simple-but-fast
implementations that can't guarantee recognition of exact
representability in all cases.

....a problem which doesn't faze hexadecimal constants in a power-of-two
radix. Admittedly this only requires reading the first nonzero digit and
calculating the normalised exponent, whereas in a decimal the whole
fractional part must be read, but I don't see it as significantly different.
However, even the simplest of algorithms
shouldn't have a problem with small integers like 3.0.

6.4.4.2p3 is a relatively minor issue; the maximum error it allows is
very tiny. The dangerous clause is 5.2.4.2.2p5:

....which doesn't apply to 3.0 == 3.0, which is what I was talking about.
It does seem to show categorically that (float)3.0 == 3.0 isn't even
remotely guaranteed though, and it's good to know about 5.2.4.2.2p5
generally, so thanks.

Phil
 
J

jameskuyper

Philip said:
James said:
Philip said:
[is 3.0 == 3.0 guaranteed?]
....
6.4.4.2p3 is a relatively minor issue; the maximum error it allows is
very tiny. The dangerous clause is 5.2.4.2.2p5:

...which doesn't apply to 3.0 == 3.0, which is what I was talking about.
It does seem to show categorically that (float)3.0 == 3.0 isn't even
remotely guaranteed though, and it's good to know about 5.2.4.2.2p5
generally, so thanks.

I was still addressing the 3.0f == (float)3.0 issue that Old Wolfe
raised.
 
C

Chip Coldwell

Old Wolf said:
Is 3.0f required to be equal to (float)3.0 ?

No, and in general it won't be true. Try this:

#include <stdio.h>

int main(int argc, char *argv[])
{
float f = 0.1f;
double d = 0.1;
if (f == d)
puts("yes");
else
puts("no");

return 0;
}

On my system, the answer is "no". Furthermore:

$ ./ieeefloat 0.1
single 3dcccccd sign: 1 exponent: -4 mantissa: cccccd (13421773/8388608 = 160000002384185791015625E-23)
double 3fb999999999999a sign: 1 exponent: -4 mantissa: 1999999999999a (7205759403792794/4503599627370496 = 1600000000000000088817841970012523233890533447265625E-51)

Chip
 

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

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top