From 4f0e77290636a5b8b8310af4f1561d2ca35a32f1 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Tue, 23 Jul 2024 20:58:45 +0200 Subject: [PATCH] xstrtod, xstrtold: Add documentation. * lib/xstrtod.h (xstrtod, xstrtold): Add comments. * lib/xstrtod.c (XSTRTOD): Improve comments. --- ChangeLog | 6 ++++++ lib/xstrtod.c | 9 ++++++--- lib/xstrtod.h | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 890cd57c2f..13e01f2684 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2024-07-23 Bruno Haible + + xstrtod, xstrtold: Add documentation. + * lib/xstrtod.h (xstrtod, xstrtold): Add comments. + * lib/xstrtod.c (XSTRTOD): Improve comments. + 2024-07-23 Bruno Haible xstrtold: Add tests. diff --git a/lib/xstrtod.c b/lib/xstrtod.c index 55b4bb4a8f..a9ca7e8d10 100644 --- a/lib/xstrtod.c +++ b/lib/xstrtod.c @@ -56,9 +56,10 @@ XSTRTOD (char const *str, char const **ptr, DOUBLE *result, ok = false; else { - /* Allow underflow (in which case CONVERT returns zero), - but flag overflow as an error. The user can decide - to use the limits in RESULT upon ERANGE. */ + /* Flag overflow as an error. + Flag gradual underflow as an error. + Flag flush-to-zero underflow as no error. + In either case, the caller can inspect *RESULT to get more details. */ if (val != 0 && errno == ERANGE) ok = false; } @@ -66,6 +67,8 @@ XSTRTOD (char const *str, char const **ptr, DOUBLE *result, if (ptr != NULL) *ptr = terminator; + /* Callers rely on *RESULT even when !ok. */ *result = val; + return ok; } diff --git a/lib/xstrtod.h b/lib/xstrtod.h index 9ae4be13da..8ceca6c433 100644 --- a/lib/xstrtod.h +++ b/lib/xstrtod.h @@ -26,8 +26,55 @@ extern "C" { #endif +/* Converts the initial portion of the string starting at STR (if PTR != NULL) + or the entire string starting at STR (if PTR == NULL) to a number of type + 'double'. + CONVERT should be a conversion function with the same calling conventions + as strtod, such as strtod or c_strtod. + If successful, it returns true, with *RESULT set to the result. + If it fails, it returns false, with *RESULT and errno set. + In total, there are the following cases: + + Condition RET *RESULT errno + ----------------------------------------------------------------------------- + conversion error: no number parsed false 0.0 EINVAL or 0 + PTR == NULL, number parsed but junk after number false value 0 + NaN true NaN 0 + ±Infinity true ±HUGE_VAL 0 + overflow false ±HUGE_VAL ERANGE + gradual underflow [!MSVC] false near zero ERANGE + gradual underflow [MSVC] true near zero 0 + flush-to-zero underflow true ±0.0 ERANGE + other finite value true value 0 + + In both cases, if PTR != NULL, *PTR is set to point to the character after + the parsed number. */ bool xstrtod (const char *str, const char **ptr, double *result, double (*convert) (char const *, char **)); + +/* Converts the initial portion of the string starting at STR (if PTR != NULL) + or the entire string starting at STR (if PTR == NULL) to a number of type + 'long double'. + CONVERT should be a conversion function with the same calling conventions + as strtold, such as strtold or c_strtold. + If successful, it returns true, with *RESULT set to the result. + If it fails, it returns false, with *RESULT and errno set. + In total, there are the following cases: + + Condition RET *RESULT errno + ----------------------------------------------------------------------------- + conversion error: no number parsed false 0.0L EINVAL or 0 + PTR == NULL, number parsed but junk after number false value 0 + NaN true NaN 0 + ±Infinity true ±HUGE_VALL 0 + overflow false ±HUGE_VALL ERANGE + gradual underflow [!MSVC] false near zero ERANGE + gradual underflow [MSVC] true near zero 0 + flush-to-zero underflow true ±0.0L ERANGE + other finite value true value 0 + + In both cases, if PTR != NULL, *PTR is set to point to the character after + the parsed number. */ bool xstrtold (const char *str, const char **ptr, long double *result, long double (*convert) (char const *, char **)); -- 2.39.5