CodeRigor

FREE LESSON

Checked numeric conversion & errno

Combine strtol/strtod, end pointers, errno and destination bounds; reject incomplete tokens, embedded NUL, whitespace, overflow and nonfinite numbers.

Numeric conversion is a small parser, not just a function call. strtol and strtod expose a converted value, an end pointer and range status. Your application supplies the remaining grammar and range rules. Our exercises parse complete tokens under the caller-provided C locale.

The end pointer exposes trailing junk
The numeric prefix converts, but a complete-token parser rejects the unconsumed suffix.
The end pointer exposes trailing junk
The numeric prefix converts, but a complete-token parser rejects the unconsumed suffix.

Adapt the input representation first

A string_view may point into a larger string with trailing bytes or into an array with no NUL at all. Make a terminated owned copy after applying the input policy. Here empty text, embedded NUL and whitespace anywhere are invalid. This avoids both an out-of-bounds scan and an accidental prefix that hides bytes after NUL.

strtol accepts leading whitespace and an optional sign by itself; the wrapper can be stricter. Use base ten for decimal counts rather than base zero, which has prefix-based behavior. strtoul also accepts a sign: an unsigned return type does not enforce a nonnegative-input grammar. atoi lacks the end-pointer and robust range reporting needed for this job.

Follow one complete example

Run this program, then change one boundary while keeping the API preconditions valid. Predict its output before pressing Run.

C++
#include <cerrno>
#include <cstdlib>
#include <cstdio>
#include <string>
int main() {
    std::string token="-25"; char* end=nullptr;
    errno=0; long value=std::strtol(token.c_str(),&end,10);
    bool complete=end!=token.c_str() && end==token.c_str()+token.size();
    bool accepted=complete && errno!=ERANGE && value>=-30 && value<=30;
    std::printf("%d %ld\n",accepted,value);
}
Three independent gates
A converted value alone cannot establish a valid application token.
Three independent gates
A converted value alone cannot establish a valid application token.

Read all the conversion evidence

Set errno to zero immediately before the call. A successful library operation can leave an earlier errno value in place. Afterward, require the end pointer to have advanced and to equal the owned string end. A zero result alone cannot distinguish "0" from a token that did not convert.

Check ERANGE and the requested destination limits before casting long to int. A long result can fit its native type and still be outside the application interval. The exercise defines invalid syntax to take precedence over range when both are present; this makes error classification deterministic rather than dependent on which check happens to be convenient.

Choose by input contract
Finite measurements need both parser status and a value policy.
Choose by input contract
Finite measurements need both parser status and a value policy.

Floating-point conversion needs a value policy

The real parser accepts strtod syntax, including exponents and hexadecimal floating tokens, but requires a finite result. NaN and infinity can be valid conversion spellings while still being invalid measurements for this API. Report them as range errors. Report both overflow and underflow when the library signals ERANGE.

Decimal points and some recognized spellings depend on locale. The lesson keeps the C locale stable instead of guessing how a localized field should be interpreted. For new C++ machine-readable integer parsers, compare this interface with from_chars: it provides an explicit range and status without a terminated copy or global errno. Existing C APIs still require understanding the original contract.

Read the return value

Predict this smaller case. The check item later changes the values, so explain the rule as well as the output.

C++
#include <cstdlib>
#include <cstdio>
int main(){char* end=nullptr; long n=std::strtol("007x",&end,10);std::printf("%ld %c\n",n,*end);}

Complete the faded example

State the missing precondition or result check before filling the code. The fill exercise supplies the rest of the implementation.

C++
std::string owned(text); char* end=nullptr;
// Fill: establish fresh range status.
long value=std::strtol(owned.c_str(), &end, 10);
// Fill: reject no conversion and trailing bytes.
// Fill: check range before narrowing.

Check your model

If errno already equals ERANGE and the next token is "0", why must the wrapper clear errno before calling strtol?

Practice the boundary

Implement the supplied parse_error enum and two functions. The caller holds LC_NUMERIC and LC_CTYPE at the "C" locale.

parse_count(text, low, high) returns an int in inclusive bounds using base-10 strtol. Optional sign and leading zeroes are accepted; base prefixes are not. low > high is invalid. parse_real(text) uses the complete finite strtod grammar (including hexadecimal floats); overflow, reported underflow (ERANGE), NaN and infinity are range errors.

Both reject empty input, whitespace anywhere, embedded NUL, no conversion and trailing unconsumed bytes as invalid. If a token has trailing junk and also overflows, invalid takes precedence. Clear errno before conversion, check the end pointer and ERANGE, and only narrow an integer after bounds checks. Never inspect a stale errno or call a NUL-terminated API on an unowned string_view. Leave global locale unchanged.

Read → six checks → two bug hunts → fill → build. A successful graded submission is evidence; reading or watching alone does not grant mastery. Review cards reinforce API choices separately.

Watch and verify

The Watch & read panel links a free lecture for the relevant background and primary API references. The lecture notes say which parts are background; the tested contract here supplies the exact wrapper policy.

C standard-library course · C library review cards · Unix/Linux systems

Watch & read

Free lectures, talks and readings that cover this skill from another angle. All resources →

Review command-line strings as input. Then use the checked conversion sequence here; the video is background, not a complete strtol/strtod error-handling tutorial.