1169. num_get not fully compatible with strto*

Section: 25.4.2.1.2 [facet.num.get.virtuals] Status: C++17 Submitter: Cosmin Truta Opened: 2009-07-04 Last modified: 2017-07-30

Priority: 3

View all other issues in [facet.num.get.virtuals].

View all issues with C++17 status.

Discussion:

As specified in the latest draft, N2914, num_get is still not fully compatible with the following C functions: strtoul, strtoull, strtof and strtod.

In C, when conversion of a string to an unsigned integer type falls outside the representable range, strtoul and strtoull return ULONG_MAX and ULLONG_MAX, respectively, regardless whether the input field represents a positive or a negative value. On the other hand, the result of num_get conversion of negative values to unsigned integer types is zero. This raises a compatibility issue.

Moreover, in C, when conversion of a string to a floating-point type falls outside the representable range, strtof, strtod and strtold return ±HUGE_VALF, ±HUGE_VAL and ±HUGE_VALL, respectively. On the other hand, the result of num_get conversion of such out-of-range floating-point values results in the most positive/negative representable value. Although many C library implementations do implement HUGE_VAL (etc.) as the highest representable (which is, usually, the infinity), this isn't required by the C standard. The C library specification makes no statement regarding the value of HUGE_VAL and friends, which potentially raises the same compatibility issue as in the above case of unsigned integers. In addition, neither C nor C++ define symbolic constants for the maximum representable floating-point values (they only do so only for the maximum representable finite floating-point values), which raises a usability issue (it would be hard for the programmer to check the result of num_get against overflow).

As such, we propose to adjust the specification of num_get to closely follow the behavior of all of its underlying C functions.

[ 2010 Rapperswil: ]

Some concern that this is changing the specification for an existing C++03 function, but it was pointed out that this was underspecified as resolved by issue 23. This is clean-up for that issue in turn. Some concern that we are trying to solve the same problem in both clause 22 and 27.

Bill: There's a change here as to whether val is stored to in an error case.

Pablo: Don't think this changes whether val is stored to or not, but changes the value that is stored.

Bill: Remembers having skirmishes with customers and testers as to whether val is stored to, and the resolution was not to store in error cases.

Howard: Believes since C++03 we made a change to always store in overflow.

Everyone took some time to review the issue.

Pablo: C++98 definitely did not store any value during an error condition.

Dietmar: Depends on the question of what is considered an error, and whether overflow is an error or not, which was the crux of LWG 23.

Pablo: Yes, but given the "zero, if the conversion function fails to convert the entire field", we are requiring every error condition to store.

Bill: When did this happen?

Alisdair: One of the last two or three meetings.

Dietmar: To store a value in case of failure is a very bad idea.

Move to Open, needs more study.

[2011-03-24 Madrid meeting]

Move to deferred

[ 2011 Bloomington ]

The proposed wording looks good, no-one sure why this was held back before. Move to Review.

[2012,Kona]

Move to Open.

THe issues is what to do with -1. Should it match 'C' or do the "sane" thing. A fix here changes behavior, but is probably what we want.

Pablo to provide wording, with help from Howard.

[2015-05-06 Lenexa: Move to Ready]

STL: I like that this uses strtof, which I think is new in C99. that avoids truncation from using atof. I have another issue ...

MC: yes LWG 2403 (stof should call strtof)

PJP: the last line is horrible, you don't assign to err, you call setstate(ios_base::failbit). Ah, no, this is inside num_get so the caller does the setstate.

MC: we need all these words. are they the right words?

JW: I'd like to take a minute to check my impl. Technically this implies a change in behaviour (from always using strtold and checking the extracted floating point value, to using the right function). Oh, we already do exactly this.

MC: Move to Ready

6 in favor, none opposed, 1 abstention

Proposed resolution:

Change 25.4.2.1.2 [facet.num.get.virtuals] as follows:

Stage 3: The sequence of chars accumulated in stage 2 (the field) is converted to a numeric value by the rules of one of the functions declared in the header <cstdlib>:

The numeric value to be stored can be one of:

The resultant numeric value is stored in val. If the conversion function fails to convert the entire field, or if the field represents a value outside the range of representable values, ios_base::failbit is assigned to err.