8000 Broken text to floating point conversion on some locales · Issue #259 · jkuhlmann/cgltf · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Broken text to floating point conversion on some locales #259

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
JulianGro opened this issue Dec 22, 2024 · 1 comment
Open

Broken text to floating point conversion on some locales #259

JulianGro opened this issue Dec 22, 2024 · 1 comment

Comments

@JulianGro
8000 Copy link
JulianGro commented Dec 22, 2024

The CGLTF_ATOF function seems to only work properly on systems with . as decimal separator. On German Linux systems for example , is used as decimal separator, which breaks the conversion. My understanding is that this is a problem with the C standard being decimal separator dependent in the first place.

In our C++ code, we work around this the following way:

float atof_locale_independent(char* str);

#define CGLTF_ATOF(str) atof_locale_independent(str)
#define CGLTF_IMPLEMENTATION
#include <cgltf.h>

float atof_locale_independent(char* str) {
    //TODO: Once we have C++17 we can use std::from_chars
    std::istringstream streamToParse(str);
    streamToParse.imbue(std::locale("C"));
    float value;
    if (!(streamToParse >> value)) {
        qDebug(modelformat) << "cgltf: Cannot parse float from string: " << str;
        return 0.0f;
    }
    return value;
}

Here is an example model which completely breaks on systems with , decimal separator: http://oaktown.pl/models/stopnie_2_1.gltf (model is CC0)

@oreo639
Copy link
oreo639 commented Feb 9, 2025

Btw, to reproduce this you need to do setlocale(LC_ALL, ""); first (since the C standard declares that the locale always defaults to C).

After that printing the atof calls confirms that the decimals are truncated.

Another way of working around this similar to .imbue():

GNU does have the non-standard atof_l/strod_l (inspired by POSIX's locale_t extension for C's locale.h):

#define CGLTF_ATOF(str) strtod_l(str, NULL, newlocale(LC_ALL, "C", NULL))

It isn't really portable though since it requires gnuXX/gnu++XX (or the equivalent _GNU_SOURCE defined before including anything else with glibc), it is supported pretty widely but not everywhere (and Windows has _create_locale(LC_ALL,"C") instead of newlocale(LC_ALL, "C", NULL)).

Also, keep in mind that calling newlocale does allocate memory, although with glibc newlocale() will return the preallocated C locale if base is null or LC_ALL_MASK is used: https://github.com/bminor/glibc/blob/bb6496b96444dfd55d7105396780f6eba14b1cd9/locale/newlocale.c#L75

Afaict the only portable way to handle this is to re-implement a locale-independent strtod/atof.

Technically speaking you can also just convert the strings to the locale format before calling strtod, like what jansson does (which is problematic for the reasons stated in the code comment):
https://github.com/akheron/jansson/blob/8b975abca1055d40637c90b1dc4585af1d7df76c/src/strconv.c#L14-L43

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants
0