Promoting unsigned long int to long int

S

santosh

pereges said:
I wrote a function for converting a string of doubles of the form
"xxxxxx yyyyyy zzzzz" into three seperate doubles. Can some one please
tell me if I done something wrong here ?

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <math.h>
#include <string.h>

int string_to_double(char *s, char **endptr, double *f)
{
int too_big = 0;

errno = 0;

*f = strtod(s, endptr);
too_big = (errno == ERANGE);

if (too_big)
{
fprintf(stderr, "OUT OF RANGE OF REPRESENTABLE VALUES
\n");
return (1);
}
else
{
if (s == *endptr)
{
fprintf(stderr, "CONVERSION OF STRING FAILED
\n");
return (1);
}
}

return (0);
}


int main(void)
{
char s[50], *ptr = NULL;
char *endptr1, *endptr2, *endptr3;
double f1, f2, f3;
int rc;

if (fgets(s, 50, stdin) == NULL)
{
fprintf(stderr, "ERROR IN INPUT STRING\n");
return (1);

Use EXIT_FAILURE instead of 1.
}
if ((ptr = strchr(s, '\n')) != NULL)
{
*ptr = '\0';
}

This isn't necessary.
rc = (string_to_double(s, &endptr1, &f1) == 0) &&
(string_to_double(endptr1, &endptr2, &f2) == 0) &&
(string_to_double(endptr2, &endptr3, &f3) == 0);


if (rc == 1)
{
printf("%f %f %f\n", f1, f2, f3);
}

return (!rc);
}

Other than what I noted, the code is, as far as I can tell, correct and
ought to work for the type of input you described.
 
S

santosh

pereges said:
I think for unsigned long and size_t, the check for '-' or any
anything other than a digit or white space is easy. This can be
achieved by simply parsing the string before passing it on to strtoul.

while (s != '\0')
{
if (isdigit(s) || isspace(s))
{
i++;
}
else
/* do error handling */
}


You will probably want to allow a '+' prefix though. Also use isxdigit
for hexadecimal strings and check octal strings for numeric characters
beyond seven.


<snip>
 
P

pereges

Use EXIT_FAILURE instead of 1.

I usually written 1 form any function (including main) when an error
occured and 0 when no error occurs. I have heard this is not protable.
If that's the case , then I will change this habit. (for main i.e.)


This isn't necessary.

Why ? What about the last character ?
 
S

santosh

pereges said:
I usually written 1 form any function (including main) when an error
occured and 0 when no error occurs. I have heard this is not protable.
If that's the case , then I will change this habit. (for main i.e.)

One is not a portable return value from main. The portable values are 0,
EXIT_SUCCESS and EXIT_FAILURE. Other values are implementation defined.
[context: about replacing the '\n' with '\0' before feeding a line to
strto*]
Why ? What about the last character ?

Conversion will stop at the first character that cannot be converted.
You can check *endptr for either '\0' or '\n' in this case (addition to
checking errno for ERANGE).
 
B

Barry Schwarz

I wrote a function for converting a string of doubles of the form
"xxxxxx yyyyyy zzzzz" into three seperate doubles. Can some one please
tell me if I done something wrong here ?

Why didn't you just execute it and confirm it is broken?

Your first mistake was posting this in your thread about unsigned
long. You couldn't use a descriptive title?
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <math.h>

And you use this header for?
#include <string.h>
Ditto.


int string_to_double(char *s, char **endptr, double *f)
{
int too_big = 0;

errno = 0;

*f = strtod(s, endptr);
too_big = (errno == ERANGE);

if (too_big)
{
fprintf(stderr, "OUT OF RANGE OF REPRESENTABLE VALUES
\n");
return (1);
}
else
{
if (s == *endptr)
{
fprintf(stderr, "CONVERSION OF STRING FAILED
\n");
return (1);
}
}

return (0);
}


int main(void)
{
char s[50], *ptr = NULL;
char *endptr1, *endptr2, *endptr3;
double f1, f2, f3;
int rc;

if (fgets(s, 50, stdin) == NULL)
{
fprintf(stderr, "ERROR IN INPUT STRING\n");
return (1);
}
if ((ptr = strchr(s, '\n')) != NULL)
{
*ptr = '\0';
}

rc = (string_to_double(s, &endptr1, &f1) == 0) &&
(string_to_double(endptr1, &endptr2, &f2) == 0) &&
(string_to_double(endptr2, &endptr3, &f3) == 0);

You probably meant to use || here. If the first call succeeds, the
return value is 0. Since && is short-circuit operator, rc will be 0
and no more calls will be made. However, ...
if (rc == 1)

....the only way rc can be 1 is if all three function calls fail and
then of course you probably don't want to print out the values. I
think you need to reverse the return value from string_to_doubles.
{
printf("%f %f %f\n", f1, f2, f3);
}

return (!rc);
}


Remove del for email
 
B

Barry Schwarz

I usually written 1 form any function (including main) when an error
occured and 0 when no error occurs. I have heard this is not protable.
If that's the case , then I will change this habit. (for main i.e.)




Why ? What about the last character ?

Why isn't what necessary? Don't you think it would be better to leave
a little context?

The issue at hand is replacing the '\n' from fgets with a '\0'. The
reason it is not necessary is that either character will cause strto??
to terminate its conversion at that point.

Unless you check the character endptr is pointing to, the replacement
buys you nothing. And even if you do check, you can check for both
characters with less code and in less CPU time without the
replacement.


Remove del for email
 
D

David Thompson

The point is that an input of "-36" is as meaningless as one of
"banana" when passed to strtoul. If you want, for some odd reason, to
accept a negative number and then check that it is positive you need
to use strtol, assign the result to a signed long, and compare that.
Seem like a waste of time, but you can do that it you like.

A negative _value_ is meaningless for an unsigned (integer) type, but
for arguably unfortunate historical reasons strtoul, plus strtoull and
strtoumax in C99, actually accept _input_ beginning with a minus sign
and return the value negated using unsigned arithmetic.
(Which is, as frequently discussed, modulo 2 up nbits.)
(As I see in another thread you have already discovered.)

As suggested elsethread, you can (pre)parse the string yourself to
check for this, and give an error or whatever, if you want.

Conversion to a signed integer type of an integer value out of range
is implementation-defined, and in C99 (explicitly) may raise a signal.
On _most_ implementations, for a signed/unsigned pair of types, half
the range of the unsigned type is out of range for the signed type.

If you really want to accept a _signed_ (possibly but not necessarily
negative) number, strol (or ll or max) is usually the right way. If
you verify that the value is nonnegative, you can then (guaranteed)
convert it to the corresponding signed type without loss of
information. If negative, or in a larger/higher-rank type and
(actually) out of range, you can still convert to unsigned _safely_,
without any impl-def or undefined behavior, but with loss of info.

- formerly david.thompson1 || achar(64) || worldnet.att.net
 
V

vippstar

Conversion to a signed integer type of an integer value out of range
is implementation-defined, and in C99 (explicitly) may raise a signal.
On _most_ implementations, for a signed/unsigned pair of types, half
the range of the unsigned type is out of range for the signed type.
It's undefined behavior, not implementation defined.
Also, it's perfectly valid if INT_MAX > UINT_MAX (though not INT_MAX >
LONG_MAX or INT_MAX > ULONG_MAX)
 
H

Harald van Dijk

It's undefined behavior, not implementation defined.

It's implementation-defined, not undefined.

6.3.1.3 Signed and unsigned integers
1 When a value with integer type is converted to another integer type
other than _Bool, if the value can be represented by the new type, it is
unchanged.
2 Otherwise, if the new type is unsigned, [...]
3 Otherwise, the new type is signed and the value cannot be represented in
it; either the result is implementation-defined or an implementation-
defined signal is raised.
Also, it's
perfectly valid if INT_MAX > UINT_MAX (though not INT_MAX > LONG_MAX or
INT_MAX > ULONG_MAX)

No, this is not valid.

6.2.5 Types
9 The range of nonnegative values of a signed integer type is a
subrange of the corresponding unsigned integer type, [...]
 
V

vippstar

It's undefined behavior, not implementation defined.

It's implementation-defined, not undefined.

6.3.1.3 Signed and unsigned integers
1 When a value with integer type is converted to another integer type
other than _Bool, if the value can be represented by the new type, it is
unchanged.
2 Otherwise, if the new type is unsigned, [...]
3 Otherwise, the new type is signed and the value cannot be represented in
it; either the result is implementation-defined or an implementation-
defined signal is raised.

Weird, in a recent discussion I've been told that %d in scanf invokes
undefined behavior because of overflow. I thought it's the same, for
example
scanf("%d", &i);
input: INT_MAX + 1
i = INT_MAX + 1; /* overflow, undefined behavior OR conversion &
implementation-defined? */
Also, it's
perfectly valid if INT_MAX > UINT_MAX (though not INT_MAX > LONG_MAX or
INT_MAX > ULONG_MAX)

No, this is not valid.

6.2.5 Types
9 The range of nonnegative values of a signed integer type is a
subrange of the corresponding unsigned integer type, [...]

Ah, thanks. :)
 
H

Harald van Dijk

On Jul 14, 7:14 am, David Thompson <[email protected]>
wrote: <snip>
Conversion to a signed integer type of an integer value out of range
is implementation-defined, and in C99 (explicitly) may raise a
signal. On _most_ implementations, for a signed/unsigned pair of
types, half the range of the unsigned type is out of range for the
signed type.
It's undefined behavior, not implementation defined.

It's implementation-defined, not undefined.

6.3.1.3 Signed and unsigned integers
1 When a value with integer type is converted to another integer type
other than _Bool, if the value can be represented by the new type,
it is unchanged.
2 Otherwise, if the new type is unsigned, [...]
3 Otherwise, the new type is signed and the value cannot be represented in
it; either the result is implementation-defined or an
implementation- defined signal is raised.

Weird, in a recent discussion I've been told that %d in scanf invokes
undefined behavior because of overflow. I thought it's the same, for
example
scanf("%d", &i);
input: INT_MAX + 1

There is no relevant conversion here; the behaviour is undefined because
the specification of scanf says the behaviour is undefined. The
specification of scanf refers to "the result of the conversion", but
"conversion" is the plain English word here, and has nothing to do with
the type conversions -- those conversions that could be made explicit by a
cast.
i = INT_MAX + 1; /* overflow, undefined behavior OR conversion &
implementation-defined? */

Overflow. If INT_MAX + 1 is evaluated, the behaviour is undefined, and you
don't even have to store it in an object for that.

If you had used

i = INT_MAX + 1u;

the addition itself would have defined behaviour. If the result is not
within the range of i, and i is signed, then 6.3.1.3p3 applies.
 
D

David Thompson

On Mon, 14 Jul 2008 04:14:03 GMT, I wrote:

Aargh! I thought I proofread this.
If you really want to accept a _signed_ (possibly but not necessarily
negative) number, strol (or ll or max) is usually the right way. If

strtol
you verify that the value is nonnegative, you can then (guaranteed)
convert it to the corresponding signed type without loss of

unsigned !
information. If negative, or in a larger/higher-rank type and
(actually) out of range, you can still convert to unsigned _safely_,
without any impl-def or undefined behavior, but with loss of info.

Sorry.
- formerly david.thompson1 || achar(64) || worldnet.att.net
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,479
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top