Richard heathfields casting operation

Discussion in 'C Programming' started by sophia.agnes@gmail.com, Nov 7, 2007.

  1. Guest

    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 *, ...))
     
    , Nov 7, 2007
    #1
    1. Advertising

  2. Chris Dollin Guest

    wrote:

    > 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.

    --
    Chris "3." Dollin

    Hewlett-Packard Limited registered no:
    registered office: Cain Road, Bracknell, Berks RG12 1HN 690597 England
     
    Chris Dollin, Nov 7, 2007
    #2
    1. Advertising

  3. 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>

    --
    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
     
    Richard Heathfield, Nov 7, 2007
    #3
  4. Richard Heathfield wrote:
    > 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.


    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 *'?

    --
    Philip Potter pgp <at> doc.ic.ac.uk
     
    Philip Potter, Nov 7, 2007
    #4
  5. Guest

    On Nov 7, 7:05 am, Richard Heathfield <> wrote:
    > 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>
    >
    > --
    > 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
     
    , Nov 7, 2007
    #5
  6. wrote:
    > i compiled and executed your program:-
    >

    <snip>

    > 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

    --
    Philip Potter pgp <at> doc.ic.ac.uk
     
    Philip Potter, Nov 7, 2007
    #6
  7. James Kuyper Guest

    wrote:
    ....
    > 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.
     
    James Kuyper, Nov 7, 2007
    #7
  8. Philip Potter said:

    > Richard Heathfield wrote:
    >> said:
    >>

    <snip>
    >>>
    >>> (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.

    >
    > 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.

    --
    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
     
    Richard Heathfield, Nov 7, 2007
    #8
  9. Spoon Guest

    Richard Heathfield wrote:

    > sophia.agnes wrote:
    >
    >> extern int printf(const char *, ...);
    >> void *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.


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

    (Linux/IA-64 is one such platform.)
     
    Spoon, Nov 7, 2007
    #9
  10. Richard Heathfield wrote:
    > 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.


    I feel most proud :)

    > And you just highlighted Yet Another Reason not to add
    > spurious casts.


    Indeed.

    --
    Philip Potter pgp <at> doc.ic.ac.uk
     
    Philip Potter, Nov 7, 2007
    #10
  11. Spoon <root@localhost> writes:
    > Richard Heathfield wrote:
    >> sophia.agnes wrote:
    >>> extern int printf(const char *, ...);
    >>> void *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.

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

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Looking for software development work in the San Diego area.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Nov 7, 2007
    #11
  12. In article <fgsn39$vu4$> Philip Potter <> writes:
    > Richard Heathfield wrote:
    > > 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.


    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.

    > > And you just highlighted Yet Another Reason not to add
    > > spurious casts.

    >
    > Indeed.


    Morover, the original did show how easy it is to get complex casts right.
    --
    dik t. winter, cwi, kruislaan 413, 1098 sj amsterdam, nederland, +31205924131
    home: bovenover 215, 1025 jn amsterdam, nederland; http://www.cwi.nl/~dik/
     
    Dik T. Winter, Nov 8, 2007
    #12
  13. Old Wolf Guest

    On Nov 8, 1:05 am, Richard Heathfield <> wrote:
    > said:
    > > 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.


    Is 3.0f required to be equal to (float)3.0 ?
     
    Old Wolf, Nov 8, 2007
    #13
  14. James Kuyper Guest

    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.
     
    James Kuyper, Nov 9, 2007
    #14
  15. 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.

    > In article <fgsn39$vu4$> Philip Potter <>
    > writes:
    > > Richard Heathfield wrote:
    > > > 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.

    >
    > 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! :)

    > > > And you just highlighted Yet Another Reason not to add
    > > > spurious casts.

    > >
    > > Indeed.

    >
    > 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."

    --
    Dig the sig!

    ----------- Peter 'Shaggy' Haywood ------------
    Ain't I'm a dawg!!
     
    Peter 'Shaggy' Haywood, Nov 9, 2007
    #15
  16. James Kuyper wrote:
    > 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..


    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...

    --
    Philip Potter pgp <at> doc.ic.ac.uk
     
    Philip Potter, Nov 9, 2007
    #16
  17. James Kuyper Guest

    Philip Potter wrote:
    > James Kuyper wrote:
    >> 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..

    >
    > 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.
     
    James Kuyper, Nov 9, 2007
    #17
  18. James Kuyper wrote:
    > Philip Potter wrote:
    >>> [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

    --
    Philip Potter pgp <at> doc.ic.ac.uk
     
    Philip Potter, Nov 9, 2007
    #18
  19. Guest

    Philip Potter wrote:
    > James Kuyper wrote:
    > > Philip Potter wrote:
    > >>> [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.
     
    , Nov 9, 2007
    #19
  20. Old Wolf <> writes:

    > On Nov 8, 1:05 am, Richard Heathfield <> wrote:
    >> said:
    >> > 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.

    >
    > 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

    --
    Charles M. "Chip" Coldwell
    "Turn on, log in, tune out"
    Somerville, Massachusetts, New England
     
    Chip Coldwell, Nov 9, 2007
    #20
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. david ullua
    Replies:
    13
    Views:
    669
  2. raan
    Replies:
    2
    Views:
    452
  3. Replies:
    47
    Views:
    1,102
    Charlie Gordon
    Nov 16, 2007
  4. Nomen Nescio

    posible minour buggs in dick heathfields book

    Nomen Nescio, Oct 27, 2008, in forum: C Programming
    Replies:
    0
    Views:
    243
    Nomen Nescio
    Oct 27, 2008
  5. Buzz Lightyear
    Replies:
    10
    Views:
    1,124
    Alexander Bartolich
    Aug 12, 2009
Loading...

Share This Page