Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #58570 > unrolled thread
| Started by | jacob navia <jacob@jacob.remcomp.fr> |
|---|---|
| First post | 2015-03-21 12:09 +0100 |
| Last post | 2015-03-29 11:30 +1300 |
| Articles | 20 on this page of 96 — 20 participants |
Back to article view | Back to comp.lang.c
Code for strtol/strtoul jacob navia <jacob@jacob.remcomp.fr> - 2015-03-21 12:09 +0100
Re: Code for strtol/strtoul Bartc <bc@freeuk.com> - 2015-03-21 11:33 +0000
Re: Code for strtol/strtoul Bartc <bc@freeuk.com> - 2015-03-21 11:47 +0000
Re: Code for strtol/strtoul Greg Martin <greg.at.softsprocket@dot.com> - 2015-03-21 15:58 +0000
Re: Code for strtol/strtoul Lőrinczy Zsigmond <nospam@for.me> - 2015-03-21 16:10 +0100
Re: Code for strtol/strtoul jacob navia <jacob@jacob.remcomp.fr> - 2015-03-21 16:34 +0100
Re: Code for strtol/strtoul Kaz Kylheku <kaz@kylheku.com> - 2015-03-21 16:10 +0000
Re: Code for strtol/strtoul James Kuyper <jameskuyper@verizon.net> - 2015-03-21 12:53 -0400
Re: Code for strtol/strtoul Keith Thompson <kst-u@mib.org> - 2015-03-21 14:18 -0700
Re: Code for strtol/strtoul jacob navia <jacob@jacob.remcomp.fr> - 2015-03-21 22:46 +0100
Re: Code for strtol/strtoul Keith Thompson <kst-u@mib.org> - 2015-03-21 15:23 -0700
Re: Code for strtol/strtoul jacob navia <jacob@jacob.remcomp.fr> - 2015-03-21 23:42 +0100
Re: Code for strtol/strtoul Keith Thompson <kst-u@mib.org> - 2015-03-21 16:06 -0700
Re: Code for strtol/strtoul jacob navia <jacob@jacob.remcomp.fr> - 2015-03-22 00:29 +0100
Re: Code for strtol/strtoul Keith Thompson <kst-u@mib.org> - 2015-03-21 20:18 -0700
Re: Code for strtol/strtoul Keith Thompson <kst-u@mib.org> - 2015-03-21 15:54 -0700
Re: Code for strtol/strtoul jacob navia <jacob@jacob.remcomp.fr> - 2015-03-22 08:34 +0100
Re: Code for strtol/strtoul Tim Rentsch <txr@alumni.caltech.edu> - 2015-03-24 19:42 -0700
Re: Code for strtol/strtoul Keith Thompson <kst-u@mib.org> - 2015-03-25 10:40 -0700
Re: Code for strtol/strtoul Tim Rentsch <txr@alumni.caltech.edu> - 2015-03-25 16:17 -0700
Re: Code for strtol/strtoul Keith Thompson <kst-u@mib.org> - 2015-03-25 20:27 -0700
Re: Code for strtol/strtoul Tim Rentsch <txr@alumni.caltech.edu> - 2015-03-28 09:08 -0700
Re: Code for strtol/strtoul Greg Martin <greg.at.softsprocket@dot.com> - 2015-03-21 15:53 +0000
Re: Code for strtol/strtoul Tim Rentsch <txr@alumni.caltech.edu> - 2015-03-24 21:50 -0700
Re: Code for strtol/strtoul jacob navia <jacob@jacob.remcomp.fr> - 2015-03-25 06:54 +0100
Re: Code for strtol/strtoul Ian Collins <ian-news@hotmail.com> - 2015-03-25 19:18 +1300
Re: Code for strtol/strtoul jacob navia <jacob@jacob.remcomp.fr> - 2015-03-25 09:57 +0100
Re: Code for strtol/strtoul Ian Collins <ian-news@hotmail.com> - 2015-03-26 07:07 +1300
Re: Code for strtol/strtoul Ian Collins <ian-news@hotmail.com> - 2015-03-26 14:22 +1300
Re: Code for strtol/strtoul asetofsymbols@gmail.com - 2015-03-26 00:17 -0700
Re: Code for strtol/strtoul Ian Collins <ian-news@hotmail.com> - 2015-03-28 12:07 +1300
Re: Code for strtol/strtoul asetofsymbols@gmail.com - 2015-03-28 02:53 -0700
Re: Code for strtol/strtoul Tim Rentsch <txr@alumni.caltech.edu> - 2015-03-25 08:19 -0700
Re: Code for strtol/strtoul Tim Rentsch <txr@alumni.caltech.edu> - 2015-03-28 16:13 -0700
Re: Code for strtol/strtoul Greg Martin <greg.at.softsprocket@dot.com> - 2015-03-25 13:42 +0000
Re: Code for strtol/strtoul Tim Rentsch <txr@alumni.caltech.edu> - 2015-03-25 17:20 -0700
Re: Code for strtol/strtoul Kaz Kylheku <kaz@kylheku.com> - 2015-03-26 04:16 +0000
Re: Code for strtol/strtoul asetofsymbols@gmail.com - 2015-03-26 00:27 -0700
Re: Code for strtol/strtoul Kaz Kylheku <kaz@kylheku.com> - 2015-03-26 13:44 +0000
Re: Code for strtol/strtoul fir <profesor.fir@gmail.com> - 2015-03-26 07:13 -0700
Re: Code for strtol/strtoul asetofsymbols@gmail.com - 2015-03-26 08:30 -0700
Re: Code for strtol/strtoul raltbos@xs4all.nl (Richard Bos) - 2015-03-29 15:13 +0000
Re: Code for strtol/strtoul Tim Rentsch <txr@alumni.caltech.edu> - 2015-03-28 09:47 -0700
Re: Code for strtol/strtoul Greg Martin <greg.at.softsprocket@dot.com> - 2015-03-26 15:00 +0000
Re: Code for strtol/strtoul Ian Collins <ian-news@hotmail.com> - 2015-03-27 07:12 +1300
Re: Code for strtol/strtoul Bartc <bc@freeuk.com> - 2015-03-26 19:11 +0000
Re: Code for strtol/strtoul Malcolm McLean <malcolm.mclean5@btinternet.com> - 2015-03-26 15:09 -0700
Re: Code for strtol/strtoul Richard Heathfield <rjh@cpax.org.uk> - 2015-03-26 22:13 +0000
Re: Code for strtol/strtoul Malcolm McLean <malcolm.mclean5@btinternet.com> - 2015-03-26 15:20 -0700
Re: Code for strtol/strtoul raltbos@xs4all.nl (Richard Bos) - 2015-03-30 09:59 +0000
Re: Code for strtol/strtoul Malcolm McLean <malcolm.mclean5@btinternet.com> - 2015-03-30 06:38 -0700
Re: Code for strtol/strtoul Richard Heathfield <rjh@cpax.org.uk> - 2015-03-30 14:41 +0100
Re: Code for strtol/strtoul raltbos@xs4all.nl (Richard Bos) - 2015-04-06 12:52 +0000
Re: Code for strtol/strtoul Ian Collins <ian-news@hotmail.com> - 2015-03-27 18:07 +1300
Re: Code for strtol/strtoul raltbos@xs4all.nl (Richard Bos) - 2015-03-29 15:17 +0000
Re: Code for strtol/strtoul Kaz Kylheku <kaz@kylheku.com> - 2015-03-29 15:26 +0000
Re: Code for strtol/strtoul Ian Collins <ian-news@hotmail.com> - 2015-03-30 07:09 +1300
Re: Code for strtol/strtoul raltbos@xs4all.nl (Richard Bos) - 2015-03-30 10:02 +0000
Re: Code for strtol/strtoul Bartc <bc@freeuk.com> - 2015-03-29 18:53 +0100
Re: Code for strtol/strtoul Tim Rentsch <txr@alumni.caltech.edu> - 2015-03-28 15:38 -0700
Re: Code for strtol/strtoul Robert Wessel <robertwessel2@yahoo.com> - 2015-03-21 16:48 -0500
Re: Code for strtol/strtoul Ian Collins <ian-news@hotmail.com> - 2015-03-22 20:45 +1300
Re: Code for strtol/strtoul Ike Naar <ike@iceland.freeshell.org> - 2015-03-23 09:40 +0000
Re: Code for strtol/strtoul Richard Heathfield <rjh@cpax.org.uk> - 2015-03-23 09:46 +0000
Re: Code for strtol/strtoul Reinhardt Behm <rbehm@hushmail.com> - 2015-03-23 18:44 +0800
Re: Code for strtol/strtoul Les Cargill <lcargill99@comcast.com> - 2015-03-23 20:29 -0500
Re: Code for strtol/strtoul Richard Heathfield <rjh@cpax.org.uk> - 2015-03-24 08:12 +0000
Re: Code for strtol/strtoul Robert Wessel <robertwessel2@yahoo.com> - 2015-03-23 05:27 -0500
Re: Code for strtol/strtoul Ian Collins <ian-news@hotmail.com> - 2015-03-24 07:03 +1300
Re: Code for strtol/strtoul Ike Naar <ike@iceland.freeshell.org> - 2015-03-23 22:40 +0000
Re: Code for strtol/strtoul Ian Collins <ian-news@hotmail.com> - 2015-03-24 17:17 +1300
Re: Code for strtol/strtoul Tim Rentsch <txr@alumni.caltech.edu> - 2015-03-24 21:42 -0700
Re: Code for strtol/strtoul Ian Collins <ian-news@hotmail.com> - 2015-03-25 17:55 +1300
Re: Code for strtol/strtoul Tim Rentsch <txr@alumni.caltech.edu> - 2015-03-25 08:43 -0700
Re: Code for strtol/strtoul Ian Collins <ian-news@hotmail.com> - 2015-03-26 14:15 +1300
Re: Code for strtol/strtoul Tim Rentsch <txr@alumni.caltech.edu> - 2015-03-28 14:53 -0700
Re: Code for strtol/strtoul Ian Collins <ian-news@hotmail.com> - 2015-03-29 11:04 +1300
Re: Code for strtol/strtoul Tim Rentsch <txr@alumni.caltech.edu> - 2015-03-30 12:34 -0700
Re: Code for strtol/strtoul Ian Collins <ian-news@hotmail.com> - 2015-03-31 21:20 +1300
Re: Code for strtol/strtoul Tim Rentsch <txr@alumni.caltech.edu> - 2015-03-24 22:31 -0700
Re: Code for strtol/strtoul Ian Collins <ian-news@hotmail.com> - 2015-03-25 19:30 +1300
Re: Code for strtol/strtoul Tim Rentsch <txr@alumni.caltech.edu> - 2015-03-25 08:24 -0700
Re: Code for strtol/strtoul jacob navia <jacob@jacob.remcomp.fr> - 2015-03-25 22:43 +0100
Re: Code for strtol/strtoul Ian Collins <ian-news@hotmail.com> - 2015-03-27 19:18 +1300
Re: Code for strtol/strtoul Steve Thompson <stevet810@gmail.com> - 2015-03-27 15:02 +0000
Re: Code for strtol/strtoul jacob navia <jacob@jacob.remcomp.fr> - 2015-03-27 16:10 +0100
Re: Code for strtol/strtoul Steve Thompson <stevet810@gmail.com> - 2015-03-27 22:44 +0000
Re: Code for strtol/strtoul raltbos@xs4all.nl (Richard Bos) - 2015-03-29 15:18 +0000
Re: Code for strtol/strtoul jacob navia <jacob@jacob.remcomp.fr> - 2015-03-29 17:35 +0200
Re: Code for strtol/strtoul Robert Wessel <robertwessel2@yahoo.com> - 2015-03-28 03:57 -0500
Re: Code for strtol/strtoul jacob navia <jacob@jacob.remcomp.fr> - 2015-03-28 14:09 +0100
Re: Code for strtol/strtoul Ian Collins <ian-news@hotmail.com> - 2015-03-28 22:58 +1300
Re: Code for strtol/strtoul Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-03-28 11:33 +0000
Re: Code for strtol/strtoul Ian Collins <ian-news@hotmail.com> - 2015-03-29 08:49 +1300
Re: Code for strtol/strtoul Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-03-28 22:11 +0000
Re: Code for strtol/strtoul Ian Collins <ian-news@hotmail.com> - 2015-03-29 11:30 +1300
Page 1 of 5 [1] 2 3 4 5 Next page →
| From | jacob navia <jacob@jacob.remcomp.fr> |
|---|---|
| Date | 2015-03-21 12:09 +0100 |
| Subject | Code for strtol/strtoul |
| Message-ID | <mejjh4$i17$1@speranza.aioe.org> |
After some days working in those functions, I would like to share this
work with you. I think discussing C is as interesting as discussing UFOs
( :-) ), because there some interesting issues in this code.
What to do with bad inputs? The "ever-green" question of what to do with
NULLs pops out.
What to do with unspecified situations? In this case the standard
doesn't define a lot of situations.
What to do with weird cases? For instance the sequence
strtol(
"56724399879677657653445435435456765675755435435432223444465444565466654666ULL",
&endptr,10);
I developed a formula for calculating the maximum number of digits to
read for a number base N. Is that formula correct?
What about other stuff like code readability variable names, whatever.
Thanks in advance for your comments.
jacob
P.S. COPYRIGHT:
This code is my work. If you just read it, you should give me ALL YOUR
MONEY (and more, if possible). Anyway even if you do not read it, you
are doomed since this copyright notice is copyrighted with the same
rules!
I have done all of this alone. I did NOT have any help from R.
Heathfield, that did not point me to the place in the standard where the
"Ox" was specified, nor to Mr Wessel, that did not point me to test for
errno when lost between a difference between the hybrid MSVC/gcc mingw
that confused me completely.
Enjoy!
/*----------------------------------------------------------------
* strtoul() strtol() - Conversion of a string of base n to a long
*
* Algorithm: Read into a long long, then reduce the result.
* Tested with long in 32 bits only.
/*---------------------------------------------------------------*/
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <math.h>
#include <stdlib.h>
static unsigned long Strtoul(const char *input,
char **endptr, int base, int isSignedValue)
{
char nbmax; // The maximum numerical digit that can be read
int tbase = 10; // Default base when base is zero
int MaxDigits;
int ScanSuffix = 0; // Do we scan any suffixes?
int ReadSomething=0; // Did we read something in?
char sign = 0; // If negative sign is '-'
char cbmax = 0; // Max digit that can be read for base > 10
int digit; // Digit read in
unsigned long long tvalue;
unsigned long long maxval; // Max value that doesn't overflow
unsigned long errval;
unsigned long long value = 0;
/* Store nptr into endptr immediately to save its value since
we are going to reuse input */
if (endptr) *endptr = input;
/* The value of the "base" argument should be zero or
2 <= base <= 36.
What happens with negative values of "base" or with base 1?
The standard is silent about that. We just do not accept any
other values for "base" besides those explicitely allowed
*/
if (base < 0 || base == 1 || base > 36) {
errno = ERANGE;
return 0;
}
/* Is it better to crash later when dereferencing a NULL pointer?
Or to give just an error now? */
if (input == NULL) {
errno = ERANGE;
return 0;
}
/* C99: 7.20.1.4.2 First, they decompose the input string into
three parts:
* an initial, possibly empty, sequence of white-space characters
* (as specified by the isspace function), ...
*/
while(isspace(*input)) {
input++;
}
if((*input == '-') || (*input == '+')) {
sign = *input;
input++;
}
/* C99: 7.20.1.4.5: If the subject sequence has the expected
form and the value of base is zero, the sequence of characters
starting with the first digit is interpreted as an integer
constant according to the rules of 6.4.4.1.
C99: 7.20.1.4.3: If the value of base is 16, the characters
0x or 0X may optionally precede the sequence of letters and
digits, following the sign if present.
*/
if(*input == '0' && (base == 0 || base == 16)) {
if((input[1] == 'X') || (input[1] == 'x')) {
tbase = 16;
input+=2;
}
else if (base == 0) {
tbase = 8;
/* We have read a zero! We MUST bump "ReadSomething"
because if not the trivial sequence "0" wouldn't
be recognized!! Note that "0x" is NOT a valid
sequence so we haven't read anything UNTIL we read
a number later
*/
ReadSomething=1;
input++;
}
}
/* C99: 7.20.1.4.7: If the subject sequence is empty or
does not have the expected form, no conversion is performed;
the value of nptr is stored in the object pointed to by
endptr, provided that endptr is not a null pointer.
*/
if (*input == 0 && ReadSomething == 0) return 0;
/* If we set tbase above put its value into base. We must
save the fact that if the original base was zero we should
look for an eventual suffix. Put that into the ScanSuffix
variable. Obviously ScanSuffix could be eliminated and
we could set tbase to 4876 say, since its value is no longer
used. At the end we could test if tbase is 4876. That would
save 4 bytes but make this more unreadable... Not worth */
if(base == 0) {
base = tbase;
ScanSuffix = 1;
}
if(base <= 10) {
nbmax = (char)((char)'0' + (char)(base - 1));
}
else {
nbmax = '9';
cbmax = (char)((char)'a' + (char)(base - 11));
}
if(isSignedValue) { /* We are returning a signed number */
maxval = LONG_MAX;
errval = LONG_MAX;
if(sign == '-') {
maxval = (long long)LONG_MAX+1LL;
errval = (unsigned long)LONG_MIN;
}
else {
maxval = LONG_MAX;
errval = LONG_MAX;
}
}
else { /* we are returning an unsigned number */
maxval = ULONG_MAX;
errval = ULONG_MAX;
}
/*
The number of digits for a number in base "base".
Assuming 2^base is the maximum number in the given base
(in bits), we take the logarithm and divide by the
logarithm of the base to get the number of digits.
We take the ceiling since in the last position,
a whole digit must be read
*/
MaxDigits = (int)
(ceil(log(pow(2.0,sizeof(long)*CHAR_BIT))/log(base)));
/* Preliminary work is ended, we start converting the number */
while(*input && ReadSomething <= MaxDigits) {
if((*input >= '0') && (*input <= nbmax)) {
digit = *input - '0';
}
else if((*input >= 'a') && (*input <= cbmax)) {
digit = (*input - 'a') + 10;
}
else if((*input >= 'A') &&
(*input <= (char)toupper(cbmax))) {
digit = (*input - 'A') + 10;
}
else { /* invalid char. Stop. */
break;
}
/* The only usage of tvalue is to nicely appear in
our debugger to easily follow the computation.
It will be eliminated when we KNOW that there are
no bugs in left this sofwtare... :-;) */
tvalue = (value* (unsigned long)base);
value = tvalue + digit;
input++;
ReadSomething++;
}
if (*input && ReadSomething > MaxDigits) {
/* Ignore all digits */
while (((*input >= '0') && (*input <= nbmax)) ||
((*input >= 'a') && (*input <= cbmax)) ||
((*input >= 'A') &&
(*input <= (char)toupper(cbmax)))) {
input++;
}
}
if (endptr && ReadSomething && ScanSuffix) {
/* Accept U,L, UL, ULL suffixes.
All other suffixes are ignored */
if (*input == 'u' || *input == 'U') input++;
if (*input == 'l' || *input == 'L') input ++;
if (*input == 'l' || *input == 'L') input++;
}
if(endptr != NULL && ReadSomething > 0) {
*endptr = input;
}
if (value > maxval || ReadSomething > MaxDigits) {
errno = ERANGE;
value = errval;
}
else if (sign == '-') {
value = -(value&0xffffffffULL);
}
return(value);
}
/*-----------------------------------------------------------*/
/* strtoul() - convert a string of base n to an unsigned long*/
/*-----------------------------------------------------------*/
unsigned long strtoul(const char *input, char **endptr, int base)
{
return(Strtoul(input, endptr, base, 0));
}
/*-----------------------------------------------------------*/
/* strtol() - convert a string of base n to a signed long */
/*-----------------------------------------------------------*/
long strtol(const char *input, char **endptr, int base)
{
return(Strtoul(input, endptr, base, 1));
}
[toc] | [next] | [standalone]
| From | Bartc <bc@freeuk.com> |
|---|---|
| Date | 2015-03-21 11:33 +0000 |
| Message-ID | <mejktj$6v4$1@dont-email.me> |
| In reply to | #58570 |
On 21/03/2015 11:09, jacob navia wrote:
> I developed a formula for calculating the maximum number of digits to
> read for a number base N. Is that formula correct?
Assuming the maximum base is 16, I just use a table like this, which are
maximum values for unsigned numbers in each base from 2 to 16:
{
"", // 1
"1111111111111111111111111111111111111111111111111111111111111111", // 2
"11112220022122120101211020120210210211220", // 3
"33333333333333333333333333333333", // 4
"2214220303114400424121122430", // 5
"3520522010102100444244423", // 6
"45012021522523134134601", // 7
"1777777777777777777777", // 8
"145808576354216723756", // 9
"18446744073709551615", // 10
"335500516A429071284", // 11
"839365134A2A240713", // 12
"219505A9511A867B72", // 13
"8681049ADB03DB171", // 14
"2C1D56B648C6CD110", // 15
"FFFFFFFFFFFFFFFF" // 16
}
The lengths in each base are:
1: 0
2: 64
3: 41
4: 32
5: 28
6: 25
7: 23
8: 22
9: 21
10: 20
11: 19
12: 18
13: 18
14: 17
15: 17
16: 16
But, once the length of an input has been checked, if it is the maximum
length, I compare it against the maximum value to check for overflow.
(Maybe there is an easier way of doing it; I found this was simplest.)
> This code is my work. If you just read it, you should give me ALL YOUR
> MONEY (and more, if possible).
I haven't read it. Just glanced at it.
--
Bartc
[toc] | [prev] | [next] | [standalone]
| From | Bartc <bc@freeuk.com> |
|---|---|
| Date | 2015-03-21 11:47 +0000 |
| Message-ID | <mejlmu$9ge$1@dont-email.me> |
| In reply to | #58573 |
On 21/03/2015 11:33, Bartc wrote: > On 21/03/2015 11:09, jacob navia wrote: > >> I developed a formula for calculating the maximum number of digits to >> read for a number base N. Is that formula correct? > > Assuming the maximum base is 16, I just use a table like this, which are > maximum values for unsigned numbers in each base from 2 to 16: Forgot to say, this is where an input has to fit into 64 bits. (Depending on what this is used for, longer inputs can be accepted, but then they are no longer a 64-bit type.) -- Bartc
[toc] | [prev] | [next] | [standalone]
| From | Greg Martin <greg.at.softsprocket@dot.com> |
|---|---|
| Date | 2015-03-21 15:58 +0000 |
| Message-ID | <CygPw.110768$Ak4.66809@fx03.iad> |
| In reply to | #58573 |
On 2015-03-21, Bartc <bc@freeuk.com> wrote:
> On 21/03/2015 11:09, jacob navia wrote:
>
>> I developed a formula for calculating the maximum number of digits to
>> read for a number base N. Is that formula correct?
>
> Assuming the maximum base is 16, I just use a table like this, which are
> maximum values for unsigned numbers in each base from 2 to 16:
>
> {
> "", // 1
> "1111111111111111111111111111111111111111111111111111111111111111", // 2
> "11112220022122120101211020120210210211220", // 3
> "33333333333333333333333333333333", // 4
> "2214220303114400424121122430", // 5
> "3520522010102100444244423", // 6
> "45012021522523134134601", // 7
> "1777777777777777777777", // 8
> "145808576354216723756", // 9
> "18446744073709551615", // 10
> "335500516A429071284", // 11
> "839365134A2A240713", // 12
> "219505A9511A867B72", // 13
> "8681049ADB03DB171", // 14
> "2C1D56B648C6CD110", // 15
> "FFFFFFFFFFFFFFFF" // 16
> }
>
> The lengths in each base are:
>
> 1: 0
> 2: 64
> 3: 41
> 4: 32
> 5: 28
> 6: 25
> 7: 23
> 8: 22
> 9: 21
> 10: 20
> 11: 19
> 12: 18
> 13: 18
> 14: 17
> 15: 17
> 16: 16
>
> But, once the length of an input has been checked, if it is the maximum
> length, I compare it against the maximum value to check for overflow.
> (Maybe there is an easier way of doing it; I found this was simplest.)
>
It is simpler but not portable.
>> This code is my work. If you just read it, you should give me ALL YOUR
>> MONEY (and more, if possible).
>
> I haven't read it. Just glanced at it.
>
--
http://www.softsprocket.com
[toc] | [prev] | [next] | [standalone]
| From | Lőrinczy Zsigmond <nospam@for.me> |
|---|---|
| Date | 2015-03-21 16:10 +0100 |
| Message-ID | <mek1lo$nl8$1@speranza.aioe.org> |
| In reply to | #58570 |
1. Are you sure negative numbers are okay with strtoul? 1. Are you sure that suffixes like 'ull' are allowed? 2. Is this 'maxdigits' thing properly tested? For example if base=10 and bits=8, then maxdigits=2 (n<=99) is too small, maxdigits=3 (n<=999) is too big.
[toc] | [prev] | [next] | [standalone]
| From | jacob navia <jacob@jacob.remcomp.fr> |
|---|---|
| Date | 2015-03-21 16:34 +0100 |
| Message-ID | <mek32c$qs4$1@speranza.aioe.org> |
| In reply to | #58578 |
Le 21/03/2015 16:10, Lőrinczy Zsigmond a écrit : > 1. Are you sure negative numbers are okay with strtoul? > 1. Are you sure that suffixes like 'ull' are allowed? > 2. Is this 'maxdigits' thing properly tested? > For example if base=10 and bits=8, > then maxdigits=2 (n<=99) is too small, > maxdigits=3 (n<=999) is too big. Maxdigits should be 3 since you can write number up to 255 in 8 bits
[toc] | [prev] | [next] | [standalone]
| From | Kaz Kylheku <kaz@kylheku.com> |
|---|---|
| Date | 2015-03-21 16:10 +0000 |
| Message-ID | <20150321090950.491@kylheku.com> |
| In reply to | #58579 |
On 2015-03-21, jacob navia <jacob@jacob.remcomp.fr> wrote: > Le 21/03/2015 16:10, Lőrinczy Zsigmond a écrit : >> 1. Are you sure negative numbers are okay with strtoul? >> 1. Are you sure that suffixes like 'ull' are allowed? >> 2. Is this 'maxdigits' thing properly tested? >> For example if base=10 and bits=8, >> then maxdigits=2 (n<=99) is too small, >> maxdigits=3 (n<=999) is too big. > > Maxdigits should be 3 since you can write number up to 255 in 8 bits Not to mention that you can write 100 in 7 bits.
[toc] | [prev] | [next] | [standalone]
| From | James Kuyper <jameskuyper@verizon.net> |
|---|---|
| Date | 2015-03-21 12:53 -0400 |
| Message-ID | <mek7l8$d2m$1@dont-email.me> |
| In reply to | #58578 |
On 03/21/2015 11:10 AM, Lőrinczy Zsigmond wrote: > 1. Are you sure negative numbers are okay with strtoul? 7.22.1.4p3 says "optionally preceded by a plus or minus sign", 7.22.1.4p5 says "If the subject sequence begins with a minus sign, the value resulting from the conversion is negated (in the return type). In neither case is a distinction made between strtol() and strtoul(). Negation is well-defined on unsigned types - it never results in a negative value. > 1. Are you sure that suffixes like 'ull' are allowed? 7.22.1.4p3 says "... but not including an integer suffix." > 2. Is this 'maxdigits' thing properly tested? Since you didn't quote the message you're responding to, I'm not sure what "maxdigits" is about. -- James Kuyper
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2015-03-21 14:18 -0700 |
| Message-ID | <878ueqvylj.fsf@kst-u.example.com> |
| In reply to | #58578 |
Lőrinczy Zsigmond <nospam@for.me> writes:
> 1. Are you sure negative numbers are okay with strtoul?
> 1. Are you sure that suffixes like 'ull' are allowed?
> 2. Is this 'maxdigits' thing properly tested?
> For example if base=10 and bits=8,
> then maxdigits=2 (n<=99) is too small,
> maxdigits=3 (n<=999) is too big.
These questions are answered in the C standard. N1570
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
is the latest draft.
Yes, a leading + or - sign is permitted. "If the subject sequence
begins with a minus sign, the value resulting from the conversion is
negated (in the return type)." Negation is well defined for unsigned
types.
Suffixes like "ull" are not included in the "subject sequence", but
since the strto* functions convert "the longest initial subsequence
of the input string, starting with the first non-white-space
character, that is of the expected form", any such suffix will
be ignored. You can see this by passing a non-null endptr.
For example, if you call strtol with "123ULL" as the first argument,
it will convert the initial "123" to 123 and ignore the "ULL".
Which means you can also call strtol with "123XYZ" and it will do
the same thing.
This might cause problems if you pass "123ULL" and expect strtol to
consume the "ULL" suffix.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
| From | jacob navia <jacob@jacob.remcomp.fr> |
|---|---|
| Date | 2015-03-21 22:46 +0100 |
| Message-ID | <mekos0$r31$1@speranza.aioe.org> |
| In reply to | #58601 |
Le 21/03/2015 22:18, Keith Thompson a écrit : > > This might cause problems if you pass "123ULL" and expect strtol to > consume the "ULL" suffix. > Is it worth to be standard conforming here? Suffix processing is done with base 0. With this "base" all prefixes of numbers we are used to in C are recognized (starting zero for octal and 0x for hexadecimal). It would be consequent to assume that ULL and other suffixes should be recognized too.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2015-03-21 15:23 -0700 |
| Message-ID | <87zj76uh14.fsf@kst-u.example.com> |
| In reply to | #58602 |
jacob navia <jacob@jacob.remcomp.fr> writes:
> Le 21/03/2015 22:18, Keith Thompson a écrit :
>> This might cause problems if you pass "123ULL" and expect strtol to
>> consume the "ULL" suffix.
>
> Is it worth to be standard conforming here?
If you're asking my opinion, yes, absolutely. (I'm assuming the article
I'm replying to is genuine; if it isn't, jacob please let us know.)
> Suffix processing is done with base 0. With this "base" all prefixes
> of numbers we are used to in C are recognized (starting zero for octal
> and 0x for hexadecimal).
No, a suffix is never included. N1570 7.22.1.4p3 (emphasis added):
If the value of base is zero, the expected form of the subject
sequence is that of an integer constant as described in 6.4.4.1,
optionally preceded by a plus or minus sign, *but not including an
integer suffix*.
For the strto*() functions, the type of the result is determined by
which function you call. A suffix in the input string is not necessary.
But of course a superfluous suffix doesn't cause an error; it's simply
not part of the subject sequence.
> It would be consequent to assume that ULL and other suffixes should be
> recognized too.
I posted a test program, based on what you posted, the other day. Have
you tried it on the implementations you're using? I'm curious to see
the results. Here it is again:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <errno.h>
int main(void) {
printf("ULONG_MAX = %lu (0x%lx)\n", ULONG_MAX, ULONG_MAX);
errno = 0;
#if ULONG_MAX == 4294967295U
unsigned long result = strtoul("-4294967296", NULL, 0);
#elif ULONG_MAX == 18446744073709551615U
unsigned long result = strtoul("-18446744073709551616", NULL,
0);
#else
#error "Unexpected value for ULONG_MAX"
#endif
printf("result = %lu (0x%lx), errno = %d",
result, result, errno);
if (errno == ERANGE) {
printf(" (ERANGE)");
}
putchar('\n');
}
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
| From | jacob navia <jacob@jacob.remcomp.fr> |
|---|---|
| Date | 2015-03-21 23:42 +0100 |
| Message-ID | <meks59$3so$1@speranza.aioe.org> |
| In reply to | #58608 |
Le 21/03/2015 23:23, Keith Thompson a écrit :
> #include <stdio.h>
> #include <stdlib.h>
> #include <limits.h>
> #include <errno.h>
> int main(void) {
> printf("ULONG_MAX = %lu (0x%lx)\n", ULONG_MAX, ULONG_MAX);
>
> errno = 0;
> #if ULONG_MAX == 4294967295U
> unsigned long result = strtoul("-4294967296", NULL, 0);
> #elif ULONG_MAX == 18446744073709551615U
> unsigned long result = strtoul("-18446744073709551616", NULL,
> 0);
> #else
> #error "Unexpected value for ULONG_MAX"
> #endif
>
> printf("result = %lu (0x%lx), errno = %d",
> result, result, errno);
> if (errno == ERANGE) {
> printf(" (ERANGE)");
> }
> putchar('\n');
> }
This gives:
d:\lcc\test>kt
ULONG_MAX = 4294967295 (0xffffffff)
result = 4294967295 (0xffffffff), errno = 2 (ERANGE)
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2015-03-21 16:06 -0700 |
| Message-ID | <87oanmuf0p.fsf@kst-u.example.com> |
| In reply to | #58611 |
jacob navia <jacob@jacob.remcomp.fr> writes:
> Le 21/03/2015 23:23, Keith Thompson a écrit :
>> #include <stdio.h>
>> #include <stdlib.h>
>> #include <limits.h>
>> #include <errno.h>
>> int main(void) {
>> printf("ULONG_MAX = %lu (0x%lx)\n", ULONG_MAX, ULONG_MAX);
>>
>> errno = 0;
>> #if ULONG_MAX == 4294967295U
>> unsigned long result = strtoul("-4294967296", NULL, 0);
>> #elif ULONG_MAX == 18446744073709551615U
>> unsigned long result = strtoul("-18446744073709551616", NULL,
>> 0);
>> #else
>> #error "Unexpected value for ULONG_MAX"
>> #endif
>>
>> printf("result = %lu (0x%lx), errno = %d",
>> result, result, errno);
>> if (errno == ERANGE) {
>> printf(" (ERANGE)");
>> }
>> putchar('\n');
>> }
> This gives:
> d:\lcc\test>kt
> ULONG_MAX = 4294967295 (0xffffffff)
> result = 4294967295 (0xffffffff), errno = 2 (ERANGE)
Thank you.
That's the correct behavior. Is that using lcc-win?
Your original post was about an apparent error in a program compiled
with MinGW. How does this program behave when compiled and executed
using that compiler? How does it behave when compiled and executed
using Microsoft's implementation? (MinGW and Microsoft use the same
runtime library, so I expect they'll behave the same way.)
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
| From | jacob navia <jacob@jacob.remcomp.fr> |
|---|---|
| Date | 2015-03-22 00:29 +0100 |
| Message-ID | <mekurv$au8$1@speranza.aioe.org> |
| In reply to | #58617 |
Le 22/03/2015 00:06, Keith Thompson a écrit :
> jacob navia <jacob@jacob.remcomp.fr> writes:
>> Le 21/03/2015 23:23, Keith Thompson a écrit :
>>> #include <stdio.h>
>>> #include <stdlib.h>
>>> #include <limits.h>
>>> #include <errno.h>
>>> int main(void) {
>>> printf("ULONG_MAX = %lu (0x%lx)\n", ULONG_MAX, ULONG_MAX);
>>>
>>> errno = 0;
>>> #if ULONG_MAX == 4294967295U
>>> unsigned long result = strtoul("-4294967296", NULL, 0);
>>> #elif ULONG_MAX == 18446744073709551615U
>>> unsigned long result = strtoul("-18446744073709551616", NULL,
>>> 0);
>>> #else
>>> #error "Unexpected value for ULONG_MAX"
>>> #endif
>>>
>>> printf("result = %lu (0x%lx), errno = %d",
>>> result, result, errno);
>>> if (errno == ERANGE) {
>>> printf(" (ERANGE)");
>>> }
>>> putchar('\n');
>>> }
>> This gives:
>> d:\lcc\test>kt
>> ULONG_MAX = 4294967295 (0xffffffff)
>> result = 4294967295 (0xffffffff), errno = 2 (ERANGE)
>
> Thank you.
>
> That's the correct behavior. Is that using lcc-win?
>
Yes.
> Your original post was about an apparent error in a program compiled
> with MinGW. How does this program behave when compiled and executed
> using that compiler? How does it behave when compiled and executed
> using Microsoft's implementation? (MinGW and Microsoft use the same
> runtime library, so I expect they'll behave the same way.)
>
d:\lcc\test>gcc -Wall kt.c
kt.c: In function 'main':
kt.c:24:5: warning: control reaches end of non-void function [-Wreturn-type]
}
^
d:\lcc\test> rem setting it to c99 fixes the warnings
d:\lcc\test>gcc -Wall -std=c99 kt.c
d:\lcc\test>a.exe
ULONG_MAX = 4294967295 (0xffffffff)
result = 1 (0x1), errno = 34 (ERANGE)
d:\lcc\test>gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=c:/tdm-gcc-64/bin/../libexec/gcc/x86_64-w64-mingw32/4.8.1/lto-wrapper.exe
Target: x86_64-w64-mingw32
Configured with: ../../../src/gcc-4.8.1/configure
--build=x86_64-w64-mingw32 --enable-targets=all --enable-lan
guages=ada,c,c++,fortran,lto,objc,obj-c++ --enable-libgomp --enable-lto
--enable-graphite --enable-cxx-flags=-
DWINPTHREAD_STATIC --enable-libstdcxx-debug --enable-threads=posix
--enable-version-specific-runtime-libs --en
able-fully-dynamic-string --enable-libstdcxx-threads
--enable-libstdcxx-time --with-gnu-ld --disable-werror --
disable-nls --disable-win32-registry --prefix=/mingw64tdm
--with-local-prefix=/mingw64tdm --with-pkgversion=td
m64-2 --with-bugurl=http://tdm-gcc.tdragon.net/bugs
Thread model: posix
gcc version 4.8.1 (tdm64-2)
d:\lcc\test>cl kt.c
Microsoft (R) C/C++ Optimizing Compiler Version 17.00.61030 for x86
Copyright (C) Microsoft Corporation. All rights reserved.
kt.c
kt.c(11) : error C2143: syntax error : missing ';' before 'type'
d:\lcc\test> rem C99 stuff deleted. jacob
d:\lcc\test>vi kt.c
d:\lcc\test>cl kt.c
Microsoft (R) C/C++ Optimizing Compiler Version 17.00.61030 for x86
Copyright (C) Microsoft Corporation. All rights reserved.
kt.c
Microsoft (R) Incremental Linker Version 11.00.61030.0
Copyright (C) Microsoft Corporation. All rights reserved.
/out:kt.exe
kt.obj
d:\lcc\test>kt
ULONG_MAX = 4294967295 (0xffffffff)
result = 1 (0x1), errno = 34 (ERANGE)
d:\lcc\test>
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2015-03-21 20:18 -0700 |
| Message-ID | <87bnjlvhwe.fsf@kst-u.example.com> |
| In reply to | #58620 |
jacob navia <jacob@jacob.remcomp.fr> writes:
> Le 22/03/2015 00:06, Keith Thompson a écrit :
>> jacob navia <jacob@jacob.remcomp.fr> writes:
>>> Le 21/03/2015 23:23, Keith Thompson a écrit :
>>>> #include <stdio.h>
>>>> #include <stdlib.h>
>>>> #include <limits.h>
>>>> #include <errno.h>
>>>> int main(void) {
>>>> printf("ULONG_MAX = %lu (0x%lx)\n", ULONG_MAX, ULONG_MAX);
>>>>
>>>> errno = 0;
>>>> #if ULONG_MAX == 4294967295U
>>>> unsigned long result = strtoul("-4294967296", NULL, 0);
>>>> #elif ULONG_MAX == 18446744073709551615U
>>>> unsigned long result = strtoul("-18446744073709551616", NULL,
>>>> 0);
>>>> #else
>>>> #error "Unexpected value for ULONG_MAX"
>>>> #endif
>>>>
>>>> printf("result = %lu (0x%lx), errno = %d",
>>>> result, result, errno);
>>>> if (errno == ERANGE) {
>>>> printf(" (ERANGE)");
>>>> }
>>>> putchar('\n');
>>>> }
>>> This gives:
>>> d:\lcc\test>kt
>>> ULONG_MAX = 4294967295 (0xffffffff)
>>> result = 4294967295 (0xffffffff), errno = 2 (ERANGE)
>>
>> Thank you.
>>
>> That's the correct behavior. Is that using lcc-win?
>>
> Yes.
>
>> Your original post was about an apparent error in a program compiled
>> with MinGW. How does this program behave when compiled and executed
>> using that compiler? How does it behave when compiled and executed
>> using Microsoft's implementation? (MinGW and Microsoft use the same
>> runtime library, so I expect they'll behave the same way.)
>
[...]
> d:\lcc\test>gcc -Wall -std=c99 kt.c
>
> d:\lcc\test>a.exe
> ULONG_MAX = 4294967295 (0xffffffff)
> result = 1 (0x1), errno = 34 (ERANGE)
OK, that's consistent with what you wrote in your original article "More
trouble with strtoul". The behavior is clearly inconsistent with the
behavior specified in the standard. (I couldn't be sure of that until I
saw actual output from a known program.)
[...]
> d:\lcc\test>cl kt.c
> Microsoft (R) C/C++ Optimizing Compiler Version 17.00.61030 for x86
> Copyright (C) Microsoft Corporation. All rights reserved.
>
> kt.c
> kt.c(11) : error C2143: syntax error : missing ';' before 'type'
>
> d:\lcc\test> rem C99 stuff deleted. jacob
> d:\lcc\test>vi kt.c
>
> d:\lcc\test>cl kt.c
> Microsoft (R) C/C++ Optimizing Compiler Version 17.00.61030 for x86
> Copyright (C) Microsoft Corporation. All rights reserved.
>
> kt.c
> Microsoft (R) Incremental Linker Version 11.00.61030.0
> Copyright (C) Microsoft Corporation. All rights reserved.
>
> /out:kt.exe
> kt.obj
>
> d:\lcc\test>kt
> ULONG_MAX = 4294967295 (0xffffffff)
> result = 1 (0x1), errno = 34 (ERANGE)
And that's the same incorrect behavior you reported for gcc --
specifically the gcc that's packaged together with Microsoft's C runtime
by MinGW. The behavior is also inconsistent with Microsoft's
documentation of strtoul() at
<https://msdn.microsoft.com/en-us/library/5k9xb7x1.aspx>.
Conclusion: This is a bug in Microsoft's C runtime library that also
shows up in the MinGW implementation. You've reported it via the
contact address provided for MinGW; perhaps someone would care to report
it directly to Microsoft.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2015-03-21 15:54 -0700 |
| Message-ID | <87sicyufk0.fsf@kst-u.example.com> |
| In reply to | #58601 |
Keith Thompson <kst-u@mib.org> writes:
[...]
> Yes, a leading + or - sign is permitted. "If the subject sequence
> begins with a minus sign, the value resulting from the conversion is
> negated (in the return type)." Negation is well defined for unsigned
> types.
[...]
But that raises an interesting question.
Assume LONG_MAX==2147483647, LONG_MIN==-LONG_MIN-1 (32-bit
2's-complement). How does
strtol("-2147483648", NULL, 0)
work?
The obviously useful behavior is for it to return LONG_MIN and
*not* set errno. But look at the description in the standard
(N1570 7.22.1.4p5):
If the subject sequence has the expected form and the value
of base is zero, the sequence of characters starting with the
first digit is interpreted as an integer constant according to
the rules of 6.4.4.1.
So far so good; "2147483648" has the form of an integer constant.
If the subject sequence begins with a minus sign, the value
resulting from the conversion is negated (in the return type).
So *first* the value of the digit sequence is determined, and
*then* that value is negated if the string began with a minus sign.
But 2147483648 is outside the range of the return type. There is
no value of type long that you can negate and yield -2147483648,
so there's nothing that be "negated (in the return type)" to yield
that value.
In the glibc implementation, strtol("2147483648", NULL, 0) returns
LONG_MAX and sets errno to ERANGE (which is the correct behavior).
But strtol("-2147483648", NULL, 0) returns -2147483648 and doesn't
set errno -- which is perfectly sensible and useful behavior, and
probably what was intended. But I don't see how it's consistent
with the requirements stated in the standard. There *should*
be a special case for LONG_MAX and LLONG_MAX for strtoul, strtoll,
but it's not stated.
Is this a bug in the standard, or am I missing something?
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
| From | jacob navia <jacob@jacob.remcomp.fr> |
|---|---|
| Date | 2015-03-22 08:34 +0100 |
| Message-ID | <melr9i$b10$1@speranza.aioe.org> |
| In reply to | #58616 |
Le 21/03/2015 23:54, Keith Thompson a écrit :
> Keith Thompson <kst-u@mib.org> writes:
> [...]
> In the glibc implementation, strtol("2147483648", NULL, 0) returns
> LONG_MAX and sets errno to ERANGE (which is the correct behavior).
> But strtol("-2147483648", NULL, 0) returns -2147483648 and doesn't
> set errno -- which is perfectly sensible and useful behavior, and
> probably what was intended. But I don't see how it's consistent
> with the requirements stated in the standard. There *should*
> be a special case for LONG_MAX and LLONG_MAX for strtoul, strtoll,
> but it's not stated.
>
> Is this a bug in the standard, or am I missing something?
>
It is a bug in the standard of course, as you have clearly explained.
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <txr@alumni.caltech.edu> |
|---|---|
| Date | 2015-03-24 19:42 -0700 |
| Message-ID | <kfnr3sder26.fsf@x-alumni2.alumni.caltech.edu> |
| In reply to | #58616 |
Keith Thompson <kst-u@mib.org> writes:
> Keith Thompson <kst-u@mib.org> writes:
> [...]
>> Yes, a leading + or - sign is permitted. "If the subject sequence
>> begins with a minus sign, the value resulting from the conversion
>> is negated (in the return type)." Negation is well defined for
>> unsigned types.
>
> [...]
>
> But that raises an interesting question.
>
> Assume LONG_MAX==2147483647, LONG_MIN==-LONG_MIN-1 (32-bit
> 2's-complement). How does
>
> strtol("-2147483648", NULL, 0)
>
> work?
>
> The obviously useful behavior is for it to return LONG_MIN and
> *not* set errno. But look at the description in the standard
> (N1570 7.22.1.4p5):
>
> If the subject sequence has the expected form and the value
> of base is zero, the sequence of characters starting with the
> first digit is interpreted as an integer constant according to
> the rules of 6.4.4.1.
>
> So far so good; "2147483648" has the form of an integer constant.
>
> If the subject sequence begins with a minus sign, the value
> resulting from the conversion is negated (in the return type).
>
> So *first* the value of the digit sequence is determined, and
> *then* that value is negated if the string began with a minus
> sign. But 2147483648 is outside the range of the return type.
> There is no value of type long that you can negate and yield
> -2147483648, so there's nothing that be "negated (in the return
> type)" to yield that value.
>
> In the glibc implementation, strtol("2147483648", NULL, 0) returns
> LONG_MAX and sets errno to ERANGE (which is the correct behavior).
> But strtol("-2147483648", NULL, 0) returns -2147483648 and doesn't
> set errno -- which is perfectly sensible and useful behavior, and
> probably what was intended. But I don't see how it's consistent
> with the requirements stated in the standard. There *should* be a
> special case for LONG_MAX and LLONG_MAX for strtoul, strtoll, but
> it's not stated.
I assume you mean a special case for LONG_MIN and LLONG_MIN
for strtol and strtoll, respectively.
> Is this a bug in the standard, or am I missing something?
I don't know that I'd call it a bug exactly; it might be just
a poor choice of wording. For example, the text of the
Standard could be taken to mean, "if there is a minus sign,
what is produced is the negative of the subject string value,
as expressed in the type of the return type of the function."
There is not necessarily the implication that the subject value
string is converted to the return type of the function, and
/then/ negated: the text could be taken to mean the abstract
value of the subject string is negated, and that (negative)
value is then expressed in (or converted to) the type of the
return type of the function, which has error behavior if the
converted value is outside the range of representable values
for the type.
I admit the wording used is a poor choice of wording if that is
what is meant, but I don't think it's so bad as to say it's
utterly, unambiguously, and incontrovertibly wrong. Could the
wording used be improved? Certainly. Is it bad enough to rise
to the level of needing correction? That seems to be more of a
judgment call. AFAIAA there haven't been any DR's filed against
it, and the gcc people probably at least thought about it to
choose the behavior glibc ultimately delivered.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2015-03-25 10:40 -0700 |
| Message-ID | <877fu5q8lf.fsf@kst-u.example.com> |
| In reply to | #58889 |
Tim Rentsch <txr@alumni.caltech.edu> writes:
> Keith Thompson <kst-u@mib.org> writes:
[...]
>> If the subject sequence begins with a minus sign, the value
>> resulting from the conversion is negated (in the return type).
>>
>> So *first* the value of the digit sequence is determined, and
>> *then* that value is negated if the string began with a minus
>> sign. But 2147483648 is outside the range of the return type.
>> There is no value of type long that you can negate and yield
>> -2147483648, so there's nothing that be "negated (in the return
>> type)" to yield that value.
>>
>> In the glibc implementation, strtol("2147483648", NULL, 0) returns
>> LONG_MAX and sets errno to ERANGE (which is the correct behavior).
>> But strtol("-2147483648", NULL, 0) returns -2147483648 and doesn't
>> set errno -- which is perfectly sensible and useful behavior, and
>> probably what was intended. But I don't see how it's consistent
>> with the requirements stated in the standard. There *should* be a
>> special case for LONG_MAX and LLONG_MAX for strtoul, strtoll, but
>> it's not stated.
>
> I assume you mean a special case for LONG_MIN and LLONG_MIN
> for strtol and strtoll, respectively.
Yes.
>> Is this a bug in the standard, or am I missing something?
>
> I don't know that I'd call it a bug exactly; it might be just
> a poor choice of wording. For example, the text of the
> Standard could be taken to mean, "if there is a minus sign,
> what is produced is the negative of the subject string value,
> as expressed in the type of the return type of the function."
> There is not necessarily the implication that the subject value
> string is converted to the return type of the function, and
> /then/ negated: the text could be taken to mean the abstract
> value of the subject string is negated, and that (negative)
> value is then expressed in (or converted to) the type of the
> return type of the function, which has error behavior if the
> converted value is outside the range of representable values
> for the type.
I have difficulty reading "the value resulting from the conversion is
negated (in the return type)" as having a *literal* meaning other than
applying the unary "-" operator for the return type.
> I admit the wording used is a poor choice of wording if that is
> what is meant, but I don't think it's so bad as to say it's
> utterly, unambiguously, and incontrovertibly wrong. Could the
> wording used be improved? Certainly. Is it bad enough to rise
> to the level of needing correction? That seems to be more of a
> judgment call. AFAIAA there haven't been any DR's filed against
> it, and the gcc people probably at least thought about it to
> choose the behavior glibc ultimately delivered.
An interpretation consistent with the wording is that the committee
wanted to leave the behavior of strtol("-2147483648", NULL, 0)
undefined, to avoid burdening implementers for a corner case.
(glibc's behavior is consistent with that interpretation).
Assuming 32-bit long and 64-bit long long, you can't define the
LONG_MIN macro as (-2147483648), since the constant 2147483648
and the expression (-2147483648) are of type long long int.
That's an inconvenient consequence of the language rules. It's not
completely insane to think that the defined behavior of strtol()
follows the defined behavior of constant expressions in source code.
Having "-2147483648" *not* be a valid representation of that long
value in source code, but requiring strtol() to handle it correctly,
would be a special case, one that's not spelled out in the standard
(though I'm perfectly willing to believe that it was intended).
Having strtol() handle a leading unary + or - operator, but not
permitting whitespace between the sign and the digits, and not
permitting, for example, unary ~, are also special cases, but
they're spelled out.
And it wouldn't be the only case where the behavior of strtol() is
left undefined by omission; the standard doesn't say what it does if
the value of base is neither 0 nor in the range 2 to 36, inclusive.
I suspect that defining that behavior was considered less important
because the base is less likely to be derived from user input.
If I ran across an implementation of strtol() that sets errno to ERANGE
for "-2147483648", I don't think I could argue that it's non-conforming,
given the current normative wording of the standard.
On the other hand, 7.22.1.4p8 says that an error is indicated if "the
correct value is outside the range of representable values". That does
strongly suggest the intent that it should handle -2147483648 in the
obvious way.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <txr@alumni.caltech.edu> |
|---|---|
| Date | 2015-03-25 16:17 -0700 |
| Message-ID | <kfnegocacq3.fsf@x-alumni2.alumni.caltech.edu> |
| In reply to | #58935 |
Keith Thompson <kst-u@mib.org> writes:
> Tim Rentsch <txr@alumni.caltech.edu> writes:
>> Keith Thompson <kst-u@mib.org> writes:
>
> [...]
>
>>> If the subject sequence begins with a minus sign, the value
>>> resulting from the conversion is negated (in the return type).
>>>
>>> So *first* the value of the digit sequence is determined, and
>>> *then* that value is negated if the string began with a minus
>>> sign. But 2147483648 is outside the range of the return type.
>>> There is no value of type long that you can negate and yield
>>> -2147483648, so there's nothing that be "negated (in the return
>>> type)" to yield that value.
>>>
>>> In the glibc implementation, strtol("2147483648", NULL, 0) returns
>>> LONG_MAX and sets errno to ERANGE (which is the correct behavior).
>>> But strtol("-2147483648", NULL, 0) returns -2147483648 and doesn't
>>> set errno -- which is perfectly sensible and useful behavior, and
>>> probably what was intended. But I don't see how it's consistent
>>> with the requirements stated in the standard. There *should* be a
>>> special case for LONG_MAX and LLONG_MAX for strtoul, strtoll, but
>>> it's not stated.
>>
>> I assume you mean a special case for LONG_MIN and LLONG_MIN
>> for strtol and strtoll, respectively.
>
> Yes.
>
>>> Is this a bug in the standard, or am I missing something?
>>
>> I don't know that I'd call it a bug exactly; it might be just
>> a poor choice of wording. For example, the text of the
>> Standard could be taken to mean, "if there is a minus sign,
>> what is produced is the negative of the subject string value,
>> as expressed in the type of the return type of the function."
>> There is not necessarily the implication that the subject value
>> string is converted to the return type of the function, and
>> /then/ negated: the text could be taken to mean the abstract
>> value of the subject string is negated, and that (negative)
>> value is then expressed in (or converted to) the type of the
>> return type of the function, which has error behavior if the
>> converted value is outside the range of representable values
>> for the type.
>
> I have difficulty reading "the value resulting from the conversion
> is negated (in the return type)" as having a *literal* meaning
> other than applying the unary "-" operator for the return type.
> [snip elaboration]
I respect your attention to detail and also the effort you put in
to read the Standard carefully. And I'm not saying how you read
the text here is wrong. Really all I am saying is that how the
WG14 committee expects the text will be read may be different
than that, and IMO that alternate reading is not unreasonable,
even if how the text is worded is somewhat poor and no doubt
could benefit from some editing. In short, I'm dissatisfied with
what was written for this, but not so dissatisfied that I would
say it is unequivocally wrong. You okay with that?
[toc] | [prev] | [next] | [standalone]
Page 1 of 5 [1] 2 3 4 5 Next page →
Back to top | Article view | comp.lang.c
csiph-web