std::setlocale(3)

πŸ“¦ version 2024.07.05, in nixpkgs unstable, opensuse-leap 16.0

🌸 std::setlocale(3) β€” the C++ Standard Library page, but make it a group chat 🌸

okay bestie, pull up a chair because today we're talking about std::setlocale β€” yes it's from the C++ Standard Library manpage set, and yes it's lowkey the main character of "why does my decimal separator look like that" discourse. let's get into it πŸ’…


✨ NAME ✨

std::setlocale β€” literally just std::setlocale. no cap, that's the whole name. iconic minimalism.


✨ Synopsis ✨

so it lives right here bestie:

Defined in header <clocale>
char* setlocale( int category, const char* locale );

The setlocale function installs the specified system locale β€” or just a portion of it β€” as the new C locale. and like, the modifications stay in effect and influence the execution of all locale-sensitive C library functions until the next call to setlocale. that's a lot of power for one tiny function ngl. 🫢

and if locale is a null pointer? then setlocale just queries the current C locale without modifying it. it's giving "just looking, not touching" energy. πŸ™ˆ


✨ Parameters ✨

  • category β€” the locale category identifier, one of the LC_xxx macros. may be 0. πŸŽ€
  • locale β€” a system-specific locale identifier. can be "" for the user-preferred locale, or "C" for the minimal locale. ✨

✨ Return value ✨

a pointer to a narrow null-terminated string identifying the C locale after applying the changes (if any), OR a null pointer on failure. πŸ’€

here's the slay part: a copy of the returned string, along with the category used in this call to std::setlocale, may be used later in the program to restore the locale back to the state at the end of this call. so like, save it. it's your receipt. 🧾


✨ Notes ✨

okay this is the part where we get serious for a sec, bestie. 🫢

during program startup, the equivalent of std::setlocale(LC_ALL, "C"); is executed before any user code is run. so that's already happened before you even showed up. ✨

even though the return type is char*, modifying the pointed-to characters is undefined behavior. i know, i know β€” the type says you can, the universe says you shouldn't. don't do it. πŸ’€

because setlocale modifies global state which affects execution of locale-dependent functions, it is undefined behavior to call it from one thread while another thread is executing any of the following functions:

  • std::fprintf
  • std::isprint
  • std::iswdigit
  • std::localeconv
  • std::tolower
  • std::fscanf
  • std::ispunct
  • std::iswgraph
  • std::mblen
  • std::toupper
  • std::isalnum
  • std::isspace
  • std::iswlower
  • std::mbstowcs
  • std::towlower
  • std::isalpha
  • std::isupper
  • std::iswprint
  • std::mbtowc
  • std::towupper
  • std::isblank
  • std::iswalnum
  • std::iswpunct
  • std::setlocale
  • std::wcscoll
  • std::iscntrl
  • std::iswalpha
  • std::iswspace
  • std::strcoll
  • std::wcstod
  • std::isdigit
  • std::iswblank
  • std::iswupper
  • std::strerror
  • std::wcstombs
  • std::isgraph
  • std::iswcntrl
  • std::iswxdigit
  • std::strtod
  • std::wcsxfrm
  • std::islower
  • std::iswctype
  • std::isxdigit

that's 43 functions, if you were counting. which i was. πŸ”₯

POSIX also defines a locale named "POSIX", which is always accessible and is exactly equivalent to the default minimal "C" locale. so if you see "POSIX" out in the wild, that's just "C" in a little outfit. πŸ‘‘

and POSIX also specifies that the returned pointer β€” not just the contents of the pointed-to string β€” may be invalidated by subsequent calls to setlocale. so seriously, copy it. don't hoard the pointer. πŸŽ€


✨ Example ✨

// Run this code

#include <clocale>
#include <cstdio>
#include <ctime>
#include <cwchar>
#include <iterator>
#include <string>

int main()
{
    // Make a "deep copy" of current locale name.
    std::string prev_loc = std::setlocale(LC_ALL, nullptr);

    // The C locale will be UTF-8 enabled English,
    // decimal dot will be German,
    // date and time formatting will be Japanese.
    if (const char* loc = std::setlocale(LC_ALL, "en_US.UTF-8"))
        std::wprintf(L"New LC_ALL locale: %s\n", loc);
    if (const char* loc = std::setlocale(LC_NUMERIC, "de_DE.UTF-8"))
        std::wprintf(L"New LC_NUMERIC locale: %s\n", loc);
    if (const char* loc = std::setlocale(LC_TIME, "ja_JP.UTF-8"))
        std::wprintf(L"New LC_TIME locale: %s\n", loc);

    wchar_t buf[100];
    std::time_t t = std::time(nullptr);
    std::wcsftime(buf, std::size(buf), L"%A %c", std::localtime(&t));
    std::wprintf(L"Number: %.2f\nDate: %Ls\n", 3.14, buf);

    // Restore the previous locale.
    if (const char* loc = std::setlocale(LC_ALL, prev_loc.c_str()))
        std::wprintf(L"Restorred LC_ALL locale: %s\n", loc);
}

✨ Possible output ✨

New LC_ALL locale: en_US.UTF-8
New LC_NUMERIC locale: de_DE.UTF-8
New LC_TIME locale: ja_JP.UTF-8
Number: 3,14
Date: ζ—₯ζ›œζ—₯ 2022εΉ΄11月06ζ—₯ 20ζ™‚40εˆ†59η§’
Restorred LC_ALL locale: C

(and yes, Restorred is spelled like that in the original β€” we keep it exactly as it is. character for character, bestie. 🫢)


✨ See also ✨

  • LC_ALL
  • LC_COLLATE
  • LC_CTYPE
  • LC_MONETARY
  • LC_NUMERIC
  • LC_TIME

β€” these are the locale categories for std::setlocale (macro constant). the whole fam. πŸ‘‘

  • locale β€” the set of polymorphic facets that encapsulate cultural differences (class). yes that's the actual description. fancy. πŸŽ€
  • C documentation for setlocale

  1. List of Windows locale names.
  2. List of Linux locale names.

and that's the page, bestie! πŸ’– this masterpiece came to you courtesy of http://cppreference.com, version/date 2024.06.10, filed under std::setlocale(3) β€” go forth and set your locales responsibly, and remember: copy the string, not the pointer. mwah! πŸŒˆπŸ’…πŸ¦‹

πŸ“¦ where this page comes from