Get decimal separator on Mac

Viewed 117

Can someone explain to me, why I always get "." as a decimal separator on my Mac with this simple program, regardless of the system settings?

#include <iostream>

int main(int argc, const char * argv[]) {
    
    std::locale::global(std::locale());
    std::cout << "decimal separator: " << std::use_facet< std::numpunct<char> >(std::cout.getloc()).decimal_point() << "\n";
    
    return 0;
}

In the system settings I set the decimal separator to ",":

enter image description here

Note: When I execute this program on Windows, it returns the correct decimal separator, depending on the system settings.

1 Answers

The locale you pass in your call to std::locale::global uses the default constructor to make a std::locale object. That default constructor, in your case, makes a copy of std::locale::classic. From cppreference (bolding mine):

(1) Default constructor. Constructs a copy of the global C++ locale, which is the locale most recently used as the argument to std::locale::global or a copy of std::locale::classic if no call to std::locale::global has been made.

That locale, as its name implies, uses the 'classic' C++ semantics, which means using a dot as the decimal separator. I'm not sure why your Windows version behaves differently – when I run your code on my Windows 10 PC, with the system set to use a comma for the decimal separator, I still get a dot reported.


In order to report the actual current decimal separator, you can use the locale constructor with an empty string argument in the call to global, then default construct a std::locale object and use that to report the current separator:

int main(int argc, const char* argv[])
{
    std::locale::global(std::locale{ "" }); // First call sets the environment locale
    std::locale loc; // Default constructor - uses the new locale set in above call
    std::cout << "decimal separator: " << std::use_facet< std::numpunct<char> >(loc).decimal_point() << "\n";
    return 0;
}

Alternatively, if you don't actually need to change the global locale, just construct the loc object using the empty string argument:

#include <iostream>
#include <clocale>

int main(int argc, const char* argv[])
{
    std::locale loc{ "" };
    std::cout << "decimal separator: " << std::use_facet< std::numpunct<char> >(loc).decimal_point() << "\n";
    return 0;
}

And, finally, if you want to set and use the locale in the std::cout stream, you need to imbue() that stream with the specific locale:

#include <iostream>
#include <clocale>

int main(int argc, const char* argv[])
{
    std::cout << 1.234 << std::endl; // Uses default (C) separator (dot): 1.234
    std::cout.imbue(std::locale{ "" });
    std::cout << "decimal separator: " << std::use_facet< std::numpunct<char> >(std::cout.getloc()).decimal_point() << "\n";
    std::cout << 1.234 << std::endl; // Uses the system separator (comma): 1,234
    return 0;
}
Related