Using strtod

C

coder

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
 
G

Guest

coder said:
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.
 
C

coder

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

Eric Sosman

coder said:
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.
 
G

Guest

coder said:
Thanks for the reply, Harald.


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

CBFalconer

coder said:
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.securityfocus.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
 
G

Guest

CBFalconer said:
coder said:
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);
 
J

Jack Klein

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;
}
 
W

Walter Roberson

On 18 Feb 2007 10:54:18 -0800, "Harald van D?k" <[email protected]>
wrote in comp.lang.c:
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.
 
G

Gordon Burditt

You are allowed to do this as long as you bypass any possible macro
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
implementation 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.
 
C

coder

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

CBFalconer

Gordon said:
.... snip ...

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

Guest

coder said:
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(*__end)) \
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.)
 
G

Guest

CBFalconer said:
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?
 
G

Gordon Burditt

You are allowed to do this as long as you bypass any possible
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.
 
C

coder

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(*__end)) \
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.)

Ok, so the basic idea is that a macro can access variables directly,
whereas variables are passed by value to functions. Is that right?
 
G

Guest

coder said:
Ok, so the basic idea is that a macro can access variables directly,
whereas variables are passed by value to functions. Is that right?

That may be a bit oversimplified, but it's the basic idea, yes.
 

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

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top