strtod usage for "just the number"?

Discussion in 'C Programming' started by David Mathog, Apr 28, 2011.

  1. David Mathog

    David Mathog Guest

    The C string to double conversion functions all seem to operate on the
    front of the input string, turning as much of it is as possible into a
    number. In a situation where the string should be entirely the
    number, and nothing should follow it, the best I have come up with to
    handle this case is:

    char *atoken;
    char *to;
    double dtmp;
    /* lots of other stuff, generating atoken */
    errno=0;
    dtmp=strtod(atoken,&to);
    if(errno || !to || *to != '\0'){
    fprintf(stderr,"fatal error: incorrect number syntax
    %s",atoken);
    }

    It works but isn't very pretty, what with 3 tests for the various
    failure modes. Is there another way to go about this, more along the
    lines of:

    if(cvtS2D(atoken,&dtmp)){
    }

    ?
    Where the hypothetical conversion function returns 0 if the input
    string is just a number, and something
    else for all the other cases?

    Thanks,

    David Mathog
    David Mathog, Apr 28, 2011
    #1
    1. Advertising

  2. David Mathog

    Fred Guest

    On Apr 28, 12:05 pm, David Mathog <> wrote:
    > The C string to double conversion functions all seem to operate on the
    > front of the input string, turning as much of it is as possible into a
    > number.  In a situation where the string should be entirely the
    > number, and nothing should follow it, the best I have come up with to
    > handle this case is:
    >
    > char *atoken;
    > char *to;
    > double dtmp;
    >        /* lots of other stuff, generating atoken */
    >         errno=0;
    >         dtmp=strtod(atoken,&to);
    >         if(errno || !to || *to != '\0'){
    >           fprintf(stderr,"fatal error: incorrect number syntax
    > %s",atoken);
    >         }
    >
    > It works but isn't very pretty, what with 3 tests for the various
    > failure modes.  Is there another way to go about this, more along the
    > lines of:
    >
    >   if(cvtS2D(atoken,&dtmp)){
    >   }
    >
    > ?
    > Where the hypothetical conversion function returns 0 if the input
    > string is just a number, and something
    > else for all the other cases?
    >


    strtod only sets errno if a range error occurred, so you do not need
    that check to determine whether the field had bad characters in it.

    You do not need the check (*to != '\0') since if 'to' is not NULL, it
    points to the first unused character, which is guaranteed to be
    something other than the NUL character.

    That leaves you with:
    if ( to ) { ... }
    --
    Fred K
    Fred, Apr 28, 2011
    #2
    1. Advertising

  3. On Apr 28, 3:05 pm, David Mathog <> wrote:
    > The C string to double conversion functions all seem to operate on the
    > front of the input string, turning as much of it is as possible into a
    > number.  In a situation where the string should be entirely the
    > number, and nothing should follow it, the best I have come up with to
    > handle this case is:
    >
    > char *atoken;
    > char *to;
    > double dtmp;
    >        /* lots of other stuff, generating atoken */
    >         errno=0;
    >         dtmp=strtod(atoken,&to);
    >         if(errno || !to || *to != '\0'){
    >           fprintf(stderr,"fatal error: incorrect number syntax
    > %s",atoken);
    >         }
    >
    > It works but isn't very pretty, what with 3 tests for the various
    > failure modes.  Is there another way to go about this, more along the
    > lines of:
    >
    >   if(cvtS2D(atoken,&dtmp)){
    >   }
    >
    > ?
    > Where the hypothetical conversion function returns 0 if the input
    > string is just a number, and something
    > else for all the other cases?
    >


    Why not just write your own function that does what the one above
    does?
    Lets you also control whether things that strtod will accept like
    NAN or INFINITY or hex forms should count as "numbers".

    -David
    David Resnick, Apr 28, 2011
    #3
  4. Fred <> writes:

    > On Apr 28, 12:05 pm, David Mathog <> wrote:
    >> The C string to double conversion functions all seem to operate on the
    >> front of the input string, turning as much of it is as possible into a
    >> number.  In a situation where the string should be entirely the
    >> number, and nothing should follow it, the best I have come up with to
    >> handle this case is:
    >>
    >> char *atoken;
    >> char *to;
    >> double dtmp;
    >>        /* lots of other stuff, generating atoken */
    >>         errno=0;
    >>         dtmp=strtod(atoken,&to);
    >>         if(errno || !to || *to != '\0'){
    >>           fprintf(stderr,"fatal error: incorrect number syntax
    >> %s",atoken);
    >>         }
    >>
    >> It works but isn't very pretty, what with 3 tests for the various
    >> failure modes.  Is there another way to go about this, more along the
    >> lines of:
    >>
    >>   if(cvtS2D(atoken,&dtmp)){
    >>   }
    >>
    >> ?
    >> Where the hypothetical conversion function returns 0 if the input
    >> string is just a number, and something
    >> else for all the other cases?
    >>

    >
    > strtod only sets errno if a range error occurred, so you do not need
    > that check to determine whether the field had bad characters in it.
    >
    > You do not need the check (*to != '\0') since if 'to' is not NULL, it
    > points to the first unused character, which is guaranteed to be
    > something other than the NUL character.
    >
    > That leaves you with:
    > if ( to ) { ... }


    I don't think that's right. If the programmer passes a valid pointer
    as the second argument, it will get set to something -- either the value
    of the first argument if no conversion could be done or to point just
    past the converted data (even if that is a null byte).

    As a result 'to == atoken || *to' is a sufficient test for failure in
    this case.

    --
    Ben.
    Ben Bacarisse, Apr 28, 2011
    #4
  5. David Mathog

    Fred Guest

    On Apr 28, 1:30 pm, Ben Bacarisse <> wrote:
    > Fred <> writes:
    > > On Apr 28, 12:05 pm, David Mathog <> wrote:
    > >> The C string to double conversion functions all seem to operate on the
    > >> front of the input string, turning as much of it is as possible into a
    > >> number.  In a situation where the string should be entirely the
    > >> number, and nothing should follow it, the best I have come up with to
    > >> handle this case is:

    >
    > >> char *atoken;
    > >> char *to;
    > >> double dtmp;
    > >>        /* lots of other stuff, generating atoken */
    > >>         errno=0;
    > >>         dtmp=strtod(atoken,&to);
    > >>         if(errno || !to || *to != '\0'){
    > >>           fprintf(stderr,"fatal error: incorrect number syntax
    > >> %s",atoken);
    > >>         }

    >
    > >> It works but isn't very pretty, what with 3 tests for the various
    > >> failure modes.  Is there another way to go about this, more along the
    > >> lines of:

    >
    > >>   if(cvtS2D(atoken,&dtmp)){
    > >>   }

    >
    > >> ?
    > >> Where the hypothetical conversion function returns 0 if the input
    > >> string is just a number, and something
    > >> else for all the other cases?

    >
    > > strtod only sets errno if a range error occurred, so you do not need
    > > that check to determine whether the field had bad characters in it.

    >
    > > You do not need the check  (*to != '\0') since if 'to' is not NULL,it
    > > points to the first unused character, which is guaranteed to be
    > > something other than the NUL character.

    >
    > > That leaves you with:
    > >    if ( to ) { ... }

    >
    > I don't think that's right.  If the programmer passes a valid pointer
    > as the second argument, it will get set to something -- either the value
    > of the first argument if no conversion could be done or to point just
    > past the converted data (even if that is a null byte).
    >
    > As a result 'to == atoken || *to' is a sufficient test for failure in
    > this case.
    >


    You're right. The first test (to==token) is needed in case 'token'
    is empty, in which case *to is '\0', so just checking *to is
    not sufficient to test for failure.

    --
    Fred K
    Fred, Apr 28, 2011
    #5
  6. David Mathog

    Guest

    David Mathog <> wrote:
    > The C string to double conversion functions all seem to operate on the
    > front of the input string, turning as much of it is as possible into a
    > number. In a situation where the string should be entirely the
    > number, and nothing should follow it, the best I have come up with to
    > handle this case is:
    >
    > char *atoken;
    > char *to;
    > double dtmp;
    > /* lots of other stuff, generating atoken */
    > errno=0;
    > dtmp=strtod(atoken,&to);
    > if(errno || !to || *to != '\0'){
    > fprintf(stderr,"fatal error: incorrect number syntax %s",atoken);
    > }


    That isn't quite correct. strtod() will never set "to" to a null
    pointer, but it will set it equal to atoken if no conversion could be
    performed.

    > It works but isn't very pretty, what with 3 tests for the various
    > failure modes. Is there another way to go about this, more along the
    > lines of:
    >
    > if(cvtS2D(atoken,&dtmp)){
    > }


    int cvtS2D(const char * restrict p, double * restrict d)
    {
    char *q;
    errno = 0;
    *d = strtod(p, &q);
    return (errno != 0 || q == p || *q != '\0');
    }
    --
    Larry Jones

    It's going to be a long year. -- Calvin
    , Apr 28, 2011
    #6
  7. David Mathog

    katmac Guest

    On Apr 28, 3:05 pm, David Mathog <> wrote:
    > The C string to double conversion functions all seem to operate on the
    > front of the input string, turning as much of it is as possible into a
    > number.  In a situation where the string should be entirely the
    > number, and nothing should follow it, the best I have come up with to
    > handle this case is:
    >
    > char *atoken;
    > char *to;
    > double dtmp;
    >        /* lots of other stuff, generating atoken */
    >         errno=0;
    >         dtmp=strtod(atoken,&to);
    >         if(errno || !to || *to != '\0'){
    >           fprintf(stderr,"fatal error: incorrect number syntax
    > %s",atoken);
    >         }
    >
    > It works but isn't very pretty, what with 3 tests for the various
    > failure modes.  Is there another way to go about this, more along the
    > lines of:
    >
    >   if(cvtS2D(atoken,&dtmp)){
    >   }
    >
    > ?
    > Where the hypothetical conversion function returns 0 if the input
    > string is just a number, and something
    > else for all the other cases?
    >
    > Thanks,
    >
    > David Mathog


    char junk;
    return !(sscanf( atoken, "%lf%c", dtmp, &junk ) == 1);

    The same pattern can be used for anything sscanf can decode (which is
    quite a lot)
    katmac, Apr 30, 2011
    #7
  8. David Mathog

    Jorgen Grahn Guest

    On Thu, 2011-04-28, David Mathog wrote:
    > The C string to double conversion functions all seem to operate on the
    > front of the input string, turning as much of it is as possible into a
    > number. In a situation where the string should be entirely the
    > number, and nothing should follow it, the best I have come up with to
    > handle this case is:

    ....
    > It works but isn't very pretty, what with 3 tests for the various
    > failure modes. Is there another way to go about this, more along the
    > lines of:
    >
    > if(cvtS2D(atoken,&dtmp)){
    > }


    With these functions I tend to prefer returning the value and
    passing a pointer to an errno-like error:

    double cvtS2D(const char* buf, int* error);

    int err = 0;
    const double foo = cvsS2D(buf, &err);
    const double bar = cvsS2D(buf2, &err);
    if(err) // at least one input was broken

    Although tastes (and usage patterns) vary.

    /Jorgen

    --
    // Jorgen Grahn <grahn@ Oo o. . .
    \X/ snipabacken.se> O o .
    Jorgen Grahn, Apr 30, 2011
    #8
  9. katmac <> writes:
    > On Apr 28, 3:05 pm, David Mathog <> wrote:
    >> The C string to double conversion functions all seem to operate on the
    >> front of the input string, turning as much of it is as possible into a
    >> number.  In a situation where the string should be entirely the
    >> number, and nothing should follow it, the best I have come up with to
    >> handle this case is:
    >>
    >> char *atoken;
    >> char *to;
    >> double dtmp;
    >>        /* lots of other stuff, generating atoken */
    >>         errno=0;
    >>         dtmp=strtod(atoken,&to);
    >>         if(errno || !to || *to != '\0'){
    >>           fprintf(stderr,"fatal error: incorrect number syntax
    >> %s",atoken);
    >>         }
    >>
    >> It works but isn't very pretty, what with 3 tests for the various
    >> failure modes.  Is there another way to go about this, more along the
    >> lines of:
    >>
    >>   if(cvtS2D(atoken,&dtmp)){
    >>   }
    >>
    >> ?
    >> Where the hypothetical conversion function returns 0 if the input
    >> string is just a number, and something
    >> else for all the other cases?

    >
    > char junk;
    > return !(sscanf( atoken, "%lf%c", dtmp, &junk ) == 1);
    >
    > The same pattern can be used for anything sscanf can decode (which is
    > quite a lot)


    Unfortunately, if the string being scanned represents a number
    outside the range of the target type, the behavior of sscanf is
    undefined. See C99 7.19.6.2p10 (it's split across pages in n1256).

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Apr 30, 2011
    #9
  10. David Mathog

    David Mathog Guest

    On Apr 30, 7:01 am, Jorgen Grahn <> wrote:
    > On Thu, 2011-04-28, David Mathog wrote:
    >
    > >   if(cvtS2D(atoken,&dtmp)){
    > >   }

    >
    > With these functions I tend to prefer returning the value and
    > passing a pointer to an errno-like error:
    >
    >    double cvtS2D(const char* buf, int* error);
    >
    >    int err = 0;
    >    const double foo = cvsS2D(buf, &err);
    >    const double bar = cvsS2D(buf2, &err);
    >    if(err) // at least one input was broken
    >
    > Although tastes (and usage patterns) vary.


    Right, styles vary. I would have done that like:

    if(!cvtS2D(buf1,&dtmp1)){ boom("message1"); }
    if(!cvtS2D(buf2,&dtmp2)){ boom("message2"); }

    Either way, the important part is that the function returns ONE
    unambiguous status value, which I think is better than having to check
    multiple values to see if there was a problem or not. There are a lot
    of C functions that follow the second path, including and especially
    all those that depend on errno,
    where one must look at one value for "the operation did not work (or
    maybe it did but this might be a special case)" and another value for
    "the problem was (or wasn't) ...". For instance, fscanf returning
    EOF.

    Regards,

    David Mathog
    David Mathog, May 2, 2011
    #10
  11. David Mathog

    David Mathog Guest

    On Apr 28, 12:37 pm, Fred <> wrote:

    >
    > strtod only sets errno if a range error occurred, so you do not need
    > that check to determine whether the field had bad characters in it.


    Interestingly, it sets errno when the input is "[+-]inf" or "nan".
    The conversion is correct, but it sets EDOM.

    >
    > You do not need the check  (*to != '\0') since if 'to' is not NULL, it
    > points to the first unused character, which is guaranteed to be
    > something other than the NUL character.
    >
    > That leaves you with:
    >    if ( to ) { ... }


    No it doesn't (at least if (...) is supposed to be the error code):

    dtmp = strtod("foo",&to);

    has "to" as not NULL and it points to 'f', because nothing was
    converted.

    So if you want to be able to accept any valid number, including inf
    and nan,
    this seems to be the way to go:

    dtmp=strtod(atoken,&to);
    if(!to || *to){ fprintf(stderr,"PROBLEM\n"); }

    Again, this is only if atoken is to hold exactly one valid double, and
    nothing else.

    Regards,

    David Mathog
    David Mathog, May 13, 2011
    #11
    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. Leslaw Bieniasz

    std::string and strtod()

    Leslaw Bieniasz, Sep 20, 2004, in forum: C++
    Replies:
    3
    Views:
    498
    Matt Hurd
    Sep 21, 2004
  2. Mathieu Malaterre

    strtod / setlocale

    Mathieu Malaterre, Dec 13, 2004, in forum: C++
    Replies:
    1
    Views:
    543
    Buster
    Dec 13, 2004
  3. Marky C

    strtod - Dynamic Memory?

    Marky C, Apr 1, 2004, in forum: C Programming
    Replies:
    20
    Views:
    910
    Keith Thompson
    Apr 4, 2004
  4. Adam Warner

    Aliasing/Torek's strtod() experience

    Adam Warner, Jun 29, 2005, in forum: C Programming
    Replies:
    0
    Views:
    311
    Adam Warner
    Jun 29, 2005
  5. Adam Warner

    Aliasing/Torek's strtod() experience

    Adam Warner, Jun 29, 2005, in forum: C Programming
    Replies:
    9
    Views:
    389
    Michael Mair
    Jul 13, 2005
Loading...

Share This Page