Using strtod

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • coder

    Using strtod

    Hi experts,
    Is the following usage of strtod okay (p is a char pointer):

    value = strtod(p, &p);

    Is it possible that this would evoke undefined behaviour?
    Or should I use a temporary pointer and then assign its value to p?

    Thanks

  • =?utf-8?B?SGFyYWxkIHZhbiBExLNr?=

    #2
    Re: Using strtod

    coder wrote:
    Hi experts,
    Is the following usage of strtod okay (p is a char pointer):
    >
    value = strtod(p, &p);
    >
    Is it possible that this would evoke undefined behaviour?
    Or should I use a temporary pointer and then assign its value to p?
    You are allowed to do this as long as you bypass any possible macro
    definition of strtod:

    value = (strtod) (p, &p);

    But it would be cleaner to just use a temporary.

    Comment

    • coder

      #3
      Re: Using strtod

      On Feb 18, 10:47 pm, "Harald van Dijk" <true...@gmail. comwrote:
      coder wrote:
      <snip>
      Thanks for the reply, Harald.
      You are allowed to do this as long as you bypass any possible macro
      definition of strtod:
      value = (strtod) (p, &p);
      I didn't get that. Can you please explain a little more?
      But it would be cleaner to just use a temporary.

      Comment

      • Eric Sosman

        #4
        Re: Using strtod

        coder wrote:
        Hi experts,
        Is the following usage of strtod okay (p is a char pointer):
        >
        value = strtod(p, &p);
        >
        Is it possible that this would evoke undefined behaviour?
        Or should I use a temporary pointer and then assign its value to p?
        You should use a temporary, not because of undefined
        behavior (but see Harald van Dijk's response), but because
        you will need the original pointer's value when you check
        for errors. After strtod(p, &q), the condition p==q means
        strtod() was unable to convert any of the input. If you
        write strtod(p, &p) you will be unable to make the test.

        --
        Eric Sosman
        esosman@acm-dot-org.invalid

        Comment

        • =?utf-8?B?SGFyYWxkIHZhbiBExLNr?=

          #5
          Re: Using strtod

          coder wrote:
          On Feb 18, 10:47 pm, "Harald van Dijk" <true...@gmail. comwrote:
          coder wrote:
          <snip>
          >
          Thanks for the reply, Harald.
          >
          You are allowed to do this as long as you bypass any possible macro
          definition of strtod:
          value = (strtod) (p, &p);
          >
          I didn't get that. Can you please explain a little more?
          strtod(p, &p) both reads from p and writes to p. If you're using a
          function, there's no problem, because the reading from p is guaranteed
          to take place before any write. If you're using a macro, the macro is
          allowed to write to p before reading its original value.

          Comment

          • CBFalconer

            #6
            Re: Using strtod

            coder wrote:
            >
            Is the following usage of strtod okay (p is a char pointer):
            >
            value = strtod(p, &p);
            >
            Is it possible that this would evoke undefined behaviour? Or
            should I use a temporary pointer and then assign its value to p?
            Why not read the description of the function? Note the
            'restrict'. From N869:

            7.20.1.3 The strtod, strtof, and strtold functions

            Synopsis

            [#1]
            #include <stdlib.h>
            double strtod(const char * restrict nptr,
            char ** restrict endptr);
            float strtof(const char * restrict nptr,
            char ** restrict endptr);
            long double strtold(const char * restrict nptr,
            char ** restrict endptr);

            --
            <http://www.cs.auckland .ac.nz/~pgut001/pubs/vista_cost.txt>
            <http://www.securityfoc us.com/columnists/423>

            "A man who is right every time is not likely to do very much."
            -- Francis Crick, co-discover of DNA
            "There is nothing more amazing than stupidity in action."
            -- Thomas Matthews

            Comment

            • =?utf-8?B?SGFyYWxkIHZhbiBExLNr?=

              #7
              Re: Using strtod

              CBFalconer wrote:
              coder wrote:

              Is the following usage of strtod okay (p is a char pointer):

              value = strtod(p, &p);

              Is it possible that this would evoke undefined behaviour? Or
              should I use a temporary pointer and then assign its value to p?
              >
              Why not read the description of the function? Note the
              'restrict'. From N869:
              >
              7.20.1.3 The strtod, strtof, and strtold functions
              >
              Synopsis
              >
              [#1]
              #include <stdlib.h>
              double strtod(const char * restrict nptr,
              char ** restrict endptr);
              float strtof(const char * restrict nptr,
              char ** restrict endptr);
              long double strtold(const char * restrict nptr,
              char ** restrict endptr);
              I'm pretty sure restrict is irrelevant here. It means the behaviour's
              undefined if you do

              char *p;
              // ...
              strtod((char *) &p, &p);

              which could otherwise be defined, but it says nothing about

              char *p;
              // ...
              strtod(p, &p);

              Comment

              • Jack Klein

                #8
                Re: Using strtod

                On 18 Feb 2007 10:54:18 -0800, "Harald van D?k" <truedfx@gmail. com>
                wrote in comp.lang.c:
                coder wrote:
                On Feb 18, 10:47 pm, "Harald van D?k" <true...@gmail. comwrote:
                coder wrote:
                <snip>
                Thanks for the reply, Harald.
                You are allowed to do this as long as you bypass any possible macro
                definition of strtod:
                value = (strtod) (p, &p);
                I didn't get that. Can you please explain a little more?
                >
                strtod(p, &p) both reads from p and writes to p. If you're using a
                function, there's no problem, because the reading from p is guaranteed
                to take place before any write. If you're using a macro, the macro is
                allowed to write to p before reading its original value.
                Chapter and verse, please.

                There is nothing at all in the standard that states that strtod() or
                the other related strto... functions do not write to the pointer
                addressed by their second argument until after they have finished all
                use of the first argument.

                You may say that were you to implement such a function, you would not
                store the pointer value until you were finished with all other
                processing. You may say that there is no need for any reasonable
                implementation of strtod() to do so.

                But unless you can point to wording in the standard that states this,
                your answer is wrong and the OP's code produces undefined behavior.

                There is absolutely nothing at all preventing an implementation from
                providing a strtod() function like this:

                double strtod(const char * restrict nptr, char ** restrict endptr)
                {
                double result = 0.0;
                *endptr = NULL;

                while (*nptr++ != '\0')
                {
                /* processing */
                }
                *endptr = nptr;
                }

                --
                Jack Klein
                Home: http://JK-Technology.Com
                FAQs for
                comp.lang.c http://c-faq.com/
                comp.lang.c++ http://www.parashift.com/c++-faq-lite/
                alt.comp.lang.l earn.c-c++

                Comment

                • Walter Roberson

                  #9
                  Re: Using strtod

                  In article <5s8it25r29khkv ndjoi7phfvkoq3p 0po7r@4ax.com>,
                  Jack Klein <jackklein@spam cop.netwrote:
                  >On 18 Feb 2007 10:54:18 -0800, "Harald van D?k" <truedfx@gmail. com>
                  >wrote in comp.lang.c:
                  >strtod(p, &p) both reads from p and writes to p. If you're using a
                  >function, there's no problem, because the reading from p is guaranteed
                  >to take place before any write.
                  >Chapter and verse, please.
                  There is a sequence point after evaluation of the arguments
                  to a function, but before the function is called. Copies of the
                  value of the arguments are passed, not pass by reference.

                  Therefore, strtod(p,&p) would have to read p and calculate the
                  address of p, saving the read value and the address (reading
                  and saving done in any order); then the sequence point
                  requirement requires that the read and address calculation be
                  completed and the copies fully saved before the function is
                  invoked. The function would receive a value in the first
                  parameter that -happened- to contain the same contents as
                  could be found by dereferencing the pointer in the second
                  argument at that time, but there would be no way for the
                  function body to write into the pointer before that value-
                  copy had been taken because of the sequence point.

                  But as Harald pointed out, the sequence point requirements do
                  not apply to macros, so implementing as a macro could have different
                  results.
                  --
                  "No one has the right to destroy another person's belief by
                  demanding empirical evidence." -- Ann Landers

                  Comment

                  • Gordon Burditt

                    #10
                    Re: Using strtod

                    You are allowed to do this as long as you bypass any possible macro
                    definition of strtod:
                    value = (strtod) (p, &p);
                    >
                    I didn't get that. Can you please explain a little more?
                    >>
                    >strtod(p, &p) both reads from p and writes to p. If you're using a
                    >function, there's no problem, because the reading from p is guaranteed
                    >to take place before any write. If you're using a macro, the macro is
                    >allowed to write to p before reading its original value.
                    >
                    >Chapter and verse, please.
                    >
                    >There is nothing at all in the standard that states that strtod() or
                    >the other related strto... functions do not write to the pointer
                    >addressed by their second argument until after they have finished all
                    >use of the first argument.
                    C uses pass by value. If you pass the value of p as the first
                    argument and the address of p as the second argument, these values
                    are determined at the sequence point after argument evaluation but
                    before the call of the function. The value of the first argument
                    (pointer) cannot be changed by subsequent alteration of the pointer
                    pointed at by the second argument.

                    strtod() may read the value of the string pointed at by its first
                    argument. strtod() may modify the pointer pointed at by its second
                    argument, but it is not supposed to read the string originally
                    pointed at by the character pointer pointed at by the second argument.
                    (You're allowed to pass &p for an uninitialized pointer p). Since
                    there is no overlap between what's read through the first argument
                    and what's read or written through the second, there's no problem.
                    >You may say that were you to implement such a function, you would not
                    >store the pointer value until you were finished with all other
                    >processing. You may say that there is no need for any reasonable
                    >implementati on of strtod() to do so.
                    It may do so, and it doesn't matter.
                    >But unless you can point to wording in the standard that states this,
                    >your answer is wrong and the OP's code produces undefined behavior.
                    >
                    >There is absolutely nothing at all preventing an implementation from
                    >providing a strtod() function like this:
                    >
                    >double strtod(const char * restrict nptr, char ** restrict endptr)
                    >{
                    double result = 0.0;
                    *endptr = NULL;
                    The above statement cannot mess up nptr nor what it points at.
                    >
                    while (*nptr++ != '\0')
                    {
                    /* processing */
                    }
                    *endptr = nptr;
                    >}

                    Comment

                    • coder

                      #11
                      Re: Using strtod

                      On Feb 18, 11:54 pm, "Harald van Dijk" <true...@gmail. comwrote:
                      coder wrote:
                      On Feb 18, 10:47 pm, "Harald van Dijk" <true...@gmail. comwrote:
                      coder wrote:
                      <snip>
                      >
                      Thanks for the reply, Harald.
                      >
                      You are allowed to do this as long as you bypass any possible macro
                      definition of strtod:
                      value = (strtod) (p, &p);
                      >
                      I didn't get that. Can you please explain a little more?
                      >
                      strtod(p, &p) both reads from p and writes to p. If you're using a
                      function, there's no problem, because the reading from p is guaranteed
                      to take place before any write. If you're using a macro, the macro is
                      allowed to write to p before reading its original value.
                      I still don't understand fully. Can you (or someone else) please give
                      an example to illustrate this?

                      Please excuse me for my ignorance.

                      Comment

                      • CBFalconer

                        #12
                        Re: Using strtod

                        Gordon Burditt wrote:
                        >
                        >>>>You are allowed to do this as long as you bypass any possible
                        >>>>macro definition of strtod:
                        >>>>>
                        >>>>value = (strtod) (p, &p);
                        >>>>
                        >>>I didn't get that. Can you please explain a little more?
                        >>>
                        >>strtod(p, &p) both reads from p and writes to p. If you're using
                        >>a function, there's no problem, because the reading from p is
                        >>guaranteed to take place before any write. If you're using a
                        >>macro, the macro is allowed to write to p before reading its
                        >>original value.
                        >>
                        >Chapter and verse, please.
                        >>
                        >There is nothing at all in the standard that states that strtod()
                        >or the other related strto... functions do not write to the
                        >pointer addressed by their second argument until after they have
                        >finished all use of the first argument.
                        >
                        .... snip ...
                        >>
                        >There is absolutely nothing at all preventing an implementation
                        >from providing a strtod() function like this:
                        >>
                        >double strtod(const char * restrict nptr, char ** restrict endptr)
                        >{
                        > double result = 0.0;
                        > *endptr = NULL;
                        >
                        The above statement cannot mess up nptr nor what it points at.
                        However something like (never mind if it is an accurate strtod)

                        double strtod(const char *restrict nptr, char* *restrict endptr)
                        {
                        if (*nptr) {
                        do {
                        **nptr = '0';
                        } while (*(*nptr)++ != '\0');
                        }
                        return 0.0;
                        }

                        can foul everything up nicely as a result of ignoring restrict.

                        --
                        <http://www.cs.auckland .ac.nz/~pgut001/pubs/vista_cost.txt>
                        <http://www.securityfoc us.com/columnists/423>

                        "A man who is right every time is not likely to do very much."
                        -- Francis Crick, co-discover of DNA
                        "There is nothing more amazing than stupidity in action."
                        -- Thomas Matthews


                        Comment

                        • =?utf-8?B?SGFyYWxkIHZhbiBExLNr?=

                          #13
                          Re: Using strtod

                          coder wrote:
                          On Feb 18, 11:54 pm, "Harald van Dijk" <true...@gmail. comwrote:
                          coder wrote:
                          On Feb 18, 10:47 pm, "Harald van Dijk" <true...@gmail. comwrote:
                          coder wrote:
                          <snip>
                          Thanks for the reply, Harald.
                          You are allowed to do this as long as you bypass any possible macro
                          definition of strtod:
                          value = (strtod) (p, &p);
                          I didn't get that. Can you please explain a little more?
                          strtod(p, &p) both reads from p and writes to p. If you're using a
                          function, there's no problem, because the reading from p is guaranteed
                          to take place before any write. If you're using a macro, the macro is
                          allowed to write to p before reading its original value.
                          >
                          I still don't understand fully. Can you (or someone else) please give
                          an example to illustrate this?
                          >
                          Please excuse me for my ignorance.
                          Let's use strtol as another example for simplicity, and let's say the
                          compiler supports GCC-style statement-expressions and C++-style
                          references as extensions. Then, strtol might be implemented as
                          something similar to

                          #define strtol(n, end, base) \
                          ({ \
                          const char * const &__n = n; \
                          char * &__end = *end; \
                          int const &__base = base; \
                          for (__end = __n; *__end != '\0'; __end++) \
                          if (!isspace(*__en d)) \
                          break; \
                          for (; *__end != '\0'; __end++) \
                          if (!isbasedigit(* __end, __base)) \
                          break; \
                          strntol(__n, __end - __n, __base); \
                          })

                          Consider what would happen when end == &n: the final call to strntol
                          (a non-standard helper function) would pass unexpected arguments.

                          (Note: this example would need some editing to even be a potential
                          valid implementation of strtol, but the basic idea stands.)

                          Comment

                          • =?utf-8?B?SGFyYWxkIHZhbiBExLNr?=

                            #14
                            Re: Using strtod

                            CBFalconer wrote:
                            Gordon Burditt wrote:
                            >>>You are allowed to do this as long as you bypass any possible
                            >>>macro definition of strtod:
                            >>>>
                            >>>value = (strtod) (p, &p);
                            >>>
                            >>I didn't get that. Can you please explain a little more?
                            >>
                            >strtod(p, &p) both reads from p and writes to p. If you're using
                            >a function, there's no problem, because the reading from p is
                            >guaranteed to take place before any write. If you're using a
                            >macro, the macro is allowed to write to p before reading its
                            >original value.
                            >
                            Chapter and verse, please.
                            >
                            There is nothing at all in the standard that states that strtod()
                            or the other related strto... functions do not write to the
                            pointer addressed by their second argument until after they have
                            finished all use of the first argument.
                            ... snip ...
                            >
                            There is absolutely nothing at all preventing an implementation
                            from providing a strtod() function like this:
                            >
                            double strtod(const char * restrict nptr, char ** restrict endptr)
                            {
                            double result = 0.0;
                            *endptr = NULL;
                            The above statement cannot mess up nptr nor what it points at.
                            >
                            However something like (never mind if it is an accurate strtod)
                            >
                            double strtod(const char *restrict nptr, char* *restrict endptr)
                            {
                            if (*nptr) {
                            do {
                            **nptr = '0';
                            } while (*(*nptr)++ != '\0');
                            }
                            return 0.0;
                            }
                            >
                            can foul everything up nicely as a result of ignoring restrict.
                            How can you assign to **nptr when nptr is a pointer to a character?

                            Comment

                            • Gordon Burditt

                              #15
                              Re: Using strtod

                              >>>>>You are allowed to do this as long as you bypass any possible
                              >>>>>macro definition of strtod:
                              >>>>>>
                              >>>>>value = (strtod) (p, &p);
                              >>>>>
                              >>>>I didn't get that. Can you please explain a little more?
                              >>>>
                              >>>strtod(p, &p) both reads from p and writes to p. If you're using
                              >>>a function, there's no problem, because the reading from p is
                              >>>guaranteed to take place before any write. If you're using a
                              >>>macro, the macro is allowed to write to p before reading its
                              >>>original value.
                              >>>
                              >>Chapter and verse, please.
                              >>>
                              >>There is nothing at all in the standard that states that strtod()
                              >>or the other related strto... functions do not write to the
                              >>pointer addressed by their second argument until after they have
                              >>finished all use of the first argument.
                              >>
                              >... snip ...
                              >>>
                              >>There is absolutely nothing at all preventing an implementation
                              >>from providing a strtod() function like this:
                              >>>
                              >>double strtod(const char * restrict nptr, char ** restrict endptr)
                              >>{
                              >> double result = 0.0;
                              >> *endptr = NULL;
                              >>
                              >The above statement cannot mess up nptr nor what it points at.
                              >
                              >However something like (never mind if it is an accurate strtod)
                              >
                              >double strtod(const char *restrict nptr, char* *restrict endptr)
                              >{
                              if (*nptr) {
                              do {
                              **nptr = '0';
                              How can you double-dereference a const char *restrict pointer?
                              This shouldn't even compile.
                              } while (*(*nptr)++ != '\0');
                              }
                              return 0.0;
                              >}
                              If you really meant endptr rather than nptr in the above code,
                              you are dereferencing a pointer (*endptr) that is permitted to
                              be uninitialized and is supposed to be write-only.
                              >can foul everything up nicely as a result of ignoring restrict.
                              It's got a lot more problems than just ignoring restrict.

                              Comment

                              Working...