perror()4 says SUCCESS

A

arnuld

OJECTIVE: Why does perror() says SUCESSS ?

This code converts a string like "1234" into an unsingned long integer. I
wrote it following the discussion here on clc of which I have lost the
url from google http interface to newsgroup.


perror() reports error in else condition many times, I can't understand
why:


int convert_string_to_ulongint(const char* str, unsigned long* ulp)
{
int ret;
unsigned long int num;
char* p;

if(NULL == str || '\0' == *str || NULL == ulp)
{
printf("IN: %s @ %d: Invalid Args\n", __func__, __LINE__);
return VAL_ERR;
}

p = NULL;
errno = 0;
num = strtoul(str, &p, 10);

/* Error check */
if(ERANGE == errno)
{
if((0 == num) && (0 == strcmp(str, p)))
{
printf("IN: %s @%d: strtoul() could not perform conversion\n",
__func__, __LINE__);
}
else if(ULONG_MAX == num)
{
printf("IN: %s @%dp: strtoul() overflow error\n", __func__,
__LINE__);
}
else
{
printf("IN: %s @%d: strange output from strtoul()\n", __func__,
__LINE__);
}

perror("*ERROR ERANGE*");
ret = -1;
}
else if((0 == errno) && ('\0' == *p))
{
printf("IN: %s @%d: Successful Conversion by strtoul()\n",
__func__, __LINE__);
*ulp = num;
ret = 1;
}
else
{
printf("IN: %s @%d: strange conversions and errno values :(\n",
__func__, __LINE__);
printf("num = %lu, ULONG_MAX = %lu\n", num, ULONG_MAX);
perror("*ERROR in ELSE");
ret = -1;
}
 
J

Jens Thoms Toerring

arnuld said:
OJECTIVE: Why does perror() says SUCESSS ?
This code converts a string like "1234" into an unsingned long integer. I
wrote it following the discussion here on clc of which I have lost the
url from google http interface to newsgroup.

perror() reports error in else condition many times, I can't understand
why:
int convert_string_to_ulongint(const char* str, unsigned long* ulp)
{
int ret;
unsigned long int num;
char* p;
if(NULL == str || '\0' == *str || NULL == ulp)
{
printf("IN: %s @ %d: Invalid Args\n", __func__, __LINE__);
return VAL_ERR;
}
p = NULL;
errno = 0;
num = strtoul(str, &p, 10);
/* Error check */
if(ERANGE == errno)
{
if((0 == num) && (0 == strcmp(str, p)))
{
printf("IN: %s @%d: strtoul() could not perform conversion\n",
__func__, __LINE__);
}

For this ('num' being 0 and str and p pointing to the same location,
so you could actually use 'str == p' instead of strcmp()) errno
doesn't get set to ERANGE - errno gets set to ERANGE only if there
is a number to convert but it would overflow. Thus if you pass the
function a string that does not start with a number (after possible
white-space) this error isn't caught here but ends up being handled
in the very last 'else'.
else if(ULONG_MAX == num)

Everything else than this would mean your libc is broken...
{
printf("IN: %s @%dp: strtoul() overflow error\n", __func__,
__LINE__);
}
else
{
printf("IN: %s @%d: strange output from strtoul()\n", __func__,
__LINE__);
}
perror("*ERROR ERANGE*");
ret = -1;
}
else if((0 == errno) && ('\0' == *p))
{
printf("IN: %s @%d: Successful Conversion by strtoul()\n",
__func__, __LINE__);
*ulp = num;
ret = 1;
}
else
{
printf("IN: %s @%d: strange conversions and errno values :(\n",
__func__, __LINE__);
printf("num = %lu, ULONG_MAX = %lu\n", num, ULONG_MAX);
perror("*ERROR in ELSE");

Well, when you get here 'errno' is rather likely 0, and the
reason you're ending up here being that 'str' points to some-
thing that can't be interpreted as a number (or has trailing
parts that aren't a number which you also seem to consider as
being an error). And then perror() can't tell you anything else
than 'SUCCESS' because it interprets the value of 'errno'. So,
unless 'errno' isn't 0 it doesn't make to much sense calling
perror().
ret = -1;
}

I'd recommend that you change the logic a bit:

a) Check first for 'errno == 0 && *p == '\0''. That shows that
the conversion was successful.
b) If 'errno' is set to ERANGE report an overflow.
c) Otherwise something must have been wrong about the input
string: it either couldn't be converted at all (then 'p'
and 'str' will point to the same location) or there was
some trailing stuff that couldn't be interpreted as a number
(in that case you have '*p != '\0').

Another small niggle: Functions shouldn't change errno if they
succeeded. Thus I would recoment to store the original value of
errno before you set errno to 0 and then call strtoul() and reset
errno to its original value if the conversion was successful.

Regards, Jens
 
N

Nick Keighley

please include the subject in the body of your post
Subject: "perror()4 says SUCCESS Options"

I don't understand what this means
:)

OJECTIVE: Why does perror() says SUCESSS ?

there wasn't an error?
This code converts a string like "1234" into an unsingned long integer. I
wrote it following the discussion here on clc of which I have lost the
url from google http interface to newsgroup.

perror() reports error in else condition many times,

under what circumstances? I ran a slightly hacked version of your code
and there was no problem.

<snip your code>

<insert my code>
******************************************************************
/* arn.c */

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

#define __func__ "convert_string_to_ulongint"
#define VAL_ERR ERANGE

int convert_string_to_ulongint(const char* str, unsigned long* ulp)
{
int ret;
unsigned long int num;
char* p;


if(NULL == str || '\0' == *str || NULL == ulp)
{
printf("IN: %s @ %d: Invalid Args\n", __func__, __LINE__);
return VAL_ERR;
}

p = NULL;
errno = 0;
num = strtoul(str, &p, 10);

/* Error check */
if(ERANGE == errno)
{
if((0 == num) && (0 == strcmp(str, p)))
{
printf("IN: %s @%d: strtoul() could not perform conversion
\n", __func__, __LINE__);
}
else if(ULONG_MAX == num)
{
printf("IN: %s @%dp: strtoul() overflow error\n", __func__,
__LINE__);
}
else
{
printf("IN: %s @%d: strange output from strtoul()\n",
__func__, __LINE__);
}


perror("*ERROR ERANGE*");
ret = -1;
}
else if((0 == errno) && ('\0' == *p))
{
printf("IN: %s @%d: Successful Conversion by strtoul()\n",
__func__, __LINE__);
*ulp = num;
ret = 1;
}
else
{
printf("IN: %s @%d: strange conversions and errno values :(\n",
__func__, __LINE__);
printf("num = %lu, ULONG_MAX = %lu\n", num, ULONG_MAX);
perror("*ERROR in ELSE");
ret = -1;
}

return ret;
}

int main (void)
{
unsigned long result;
int retval;

if ((retval = convert_string_to_ulongint("1234", &result)) == 1)
{
printf ("conversion succeeded result was %u\n", result);
return 0;
}
else
{
printf ("conversion FAILED error flag was %d\n", retval);
return EXIT_FAILURE;
}

return 0;
}


******************************************************************
</insert my code>

Output:-
IN: convert_string_to_ulongint @52: Successful Conversion by strtoul()
conversion succeeded result was 1234
 
E

Eric Sosman

OJECTIVE: Why does perror() says SUCESSS ?

if(ERANGE == errno)
{
[... eventually call printf() ...]
}
perror("*ERROR ERANGE*");

If the penny still hasn't dropped, study this phrase from 7.5p3:
"The value of errno may be set to nonzero by a library function call
whether or not there is an error ..."
 
K

Keith Thompson

Vincenzo Mercuri said:
arnuld ha scritto: [...]
perror("*ERROR in ELSE");
[...]

Use printf("Error: %s\n", strerror(err)); instead or the Posix
compliant and thread safe "strerror_r()".

What's the advantage of that over perror()?
 
H

Harald van Dijk

Vincenzo Mercuri said:
arnuld ha scritto: [...]
       perror("*ERROR in ELSE"); [...]

Use printf("Error: %s\n", strerror(err)); instead or the Posix
compliant and thread safe "strerror_r()".

What's the advantage of that over perror()?

That it prints the error message associated with error code err,
rather than error code errno. That was the point of the other two
modifications in the message you replied to: to save the old value of
errno.
 
J

James Kuyper

Vincenzo Mercuri said:
arnuld ha scritto: [...]
perror("*ERROR in ELSE");
[...]

Use printf("Error: %s\n", strerror(err)); instead or the Posix
compliant and thread safe "strerror_r()".

What's the advantage of that over perror()?

It goes to stdin rather than stderr; though I'm not sure that counts as
and advantage; if stderr is different from stdout, I generally want
messages of this type going to stderr, not stdout. I guess that
Vincenzo's preferences are different.
 
K

Keith Thompson

Vincenzo Mercuri said:
Keith Thompson ha scritto:
Vincenzo Mercuri said:
arnuld ha scritto: [...]
perror("*ERROR in ELSE");
[...]

Use printf("Error: %s\n", strerror(err)); instead or the Posix
compliant and thread safe "strerror_r()".

What's the advantage of that over perror()?

The point I was making was that while "perror()" prints the string
representation of the *current* error described by "errno", with
"strerror()" I can print out an error message that refers to a
previously stored value of errno, such as "err" in this case.

Got it, thanks. (I'd still prefer to print the message to stderr rather
than stdout; that's easy enough to do.)
 
B

Ben Pfaff

James Kuyper said:
Vincenzo Mercuri said:
arnuld ha scritto: [...]
perror("*ERROR in ELSE");
[...]

Use printf("Error: %s\n", strerror(err)); instead or the Posix
compliant and thread safe "strerror_r()".

What's the advantage of that over perror()?

It goes to stdin rather than stderr; [...]

No.
 
J

James Kuyper

James Kuyper said:
arnuld ha scritto:
[...]
perror("*ERROR in ELSE");
[...]

Use printf("Error: %s\n", strerror(err)); instead or the Posix
compliant and thread safe "strerror_r()".

What's the advantage of that over perror()?

It goes to stdin rather than stderr; [...]

No.

Aaagh! Of course I meant stdout, not stdin. Just pretend you didn't see
that. :-}
 

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

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,051
Latest member
CarleyMcCr

Latest Threads

Top