c - strtol not changing errno -
i'm working on program performs calculations given char array represents time in format hh:mm:ss
. has parse individual time units. here's cut down version of code, focusing on hours:
unsigned long parsetime(const char *time) { int base = 10; //base 10 long hours = 60; //defaults out of range char localtime[bufsiz] //declares local array strncpy(localtime, time, bufsiz); //copies parameter array local errno = 0; //sets errno 0 char *par; //pointer par = strchr(localtime, ':'); //parses nearest ':' localtime[par - localtime] = '\0'; //sets ':' null character hours = strtol(localtime, &par, base); //updates hours parsed numbers in char array printf("errno is: %d\n", errno); //checks errno errno = 0; //resets errno 0 par++; //moves pointer past null character }
the problem if input invalid (e.g. aa:13:13
), strtol()
apparently doesn't detect error because it's not updating errno
1
, can't error handling. getting wrong?
as others have explained, strtol
may not update errno
in case cannot perform conversion. c standard documents errnor
set erange
in case converted value not fit in long
integer.
your code has other issues:
- copying string
strncpy
incorrect: in case source string longerbufsiz
,localtime
not null terminated. avoidstrncpy
, poorly understood function never fits purpose. - in case, no not need clear
:
'\0'
,strtol
stop @ first non digit character.localtime[par - localtime] = '\0';
complicated way write*par = '\0';
a simpler version this:
long parsetime(const char *time) { char *par; long hours; if (!isdigit((unsigned char)*time) { /* invalid format */ return -1; } errno = 0; hours = strtol(time, &par, 10); if (errno != 0) { /* overflow */ return -2; } /* may want check hour within decent range... */ if (*par != ':') { /* invalid format */ return -3; } par++; /* can parse further fields... */ return hours; }
i changed return type long
can check invalid format , determine error negative return value.
for simpler alternative, use sscanf
:
long parsetime(const char *time) { unsigned int hours, minutes, seconds; char c; if (sscanf(time, "%u:%u:%u%c", &hours, &minutes, &seconds, &c) != 3) { /* invalid format */ return -1; } if (hours > 1000 || minutes > 59 || seconds > 59) { /* invalid values */ return -2; } return hours * 3600l + minutes * 60 + seconds; }
this approach still accepts incorrect strings such 1: 1: 1
or 12:00000002:1
. parsing string hand seem concise , efficient solution.
Comments
Post a Comment