6

On macOS 13.3.1, strtod() does not seem to respect the locale set using uselocale(), and does not process decimal points/commas correctly. Is this a bug in macOS? Is there a workaround?

Here's a test program that demonstrates that printf() and scanf() respect the decimal point setting, but strtod() does not.


#include <locale.h>
#include <xlocale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

int main() {
    double x;
    const char *num = "12.3";
    char *end;

    // First we set the locale globally to something that uses decimal
    // commas instead of decimal points.
    const char *locname = setlocale(LC_ALL, "de_DE");
    struct lconv *lc = localeconv();
    if (strcmp(lc->decimal_point, ",")) {
        /* If decimal point is not a comma, presumably because the requested
         * locale was not available, report locale information and quit. */
        fprintf(stderr, "setlocale() returned '%s', decimal point is '%s'\n",
                locname ? locname : "NULL",
                lc->decimal_point);
        abort();
    }

    // In this locale, printf() uses decimal commas, and both scanf() and strtod()
    // assume decimal commas when reading numbers. Thus when reading 12.3, both
    // of these function stop reading as soon as they reach the '.' character.
    printf("Using locale with decimal comma:\n");
    x = 0.0;
    printf("%g\n", 12.3);
    sscanf(num, "%lf", &x);
    printf("%g\n", x);
    x = strtod(num, &end);
    printf("%g\n", x);

    // Now we set the numeric local to use decimal points in a thread-local manner
    // using the non-standard uselocale().
    locale_t c_locale = newlocale(LC_NUMERIC_MASK, "C", NULL);
    assert(c_locale != NULL);
    uselocale(c_locale);

    // Now both scanf() and strtod() should be assuming a decimal point,
    // and both should read 12.3 in full.
    printf("\nUsing locale with decimal point:\n");
    x = 0.0;
    printf("%g\n", 12.3);
    sscanf("12.3", "%lf", &x);
    printf("%g\n", x);
    x = strtod(num, &end);
    printf("%g\n", x);

    return 0;
}

Output on macOS 10.14.6 is as I expect:

Using locale with decimal comma:
12,3
12
12

Using locale with decimal point:
12.3
12.3
12.3

Output on macOS 13.3.1:

Using locale with decimal comma:
12,3
12
12

Using locale with decimal point:
12.3
12.3
12

Notice that strtod() did not read past the decimal point.


Note: This was discovered as it causes the test suite of igraph to fail. The issue report is here.

Szabolcs
  • 24,728
  • 9
  • 85
  • 174
  • Which compiler are you using? Are you using clang? – Andreas Wenzel Apr 28 '23 at 22:41
  • 1
    Yes, the default Apple Clang on each system, with the latest Xcode available for each. However, I believe this functionality is provided by the OS, and is not specific to the C compiler. I see exactly the same behaviour when trying GCC 12 from MacPorts: works on older macOS, broken on 13.3.1. – Szabolcs Apr 28 '23 at 22:52
  • 1
    Seems like a bug. A workaround could be `x = strtod_l(num, &end, c_locale);`, which works. – Mark Adler Apr 29 '23 at 01:34

1 Answers1

0

It looks like there really is a bug in MacOS Ventura standard library, see our bug report https://github.com/prusa3d/PrusaSlicer/issues/10331

bubnikv
  • 41
  • 5