localemsvcrtsetlocale

MSVCRT printf never do thousand separator grouping, right?


On Windows, using Microsoft CRT library(MSVCRT), printf/_snprintf/_snprintf_s/_snprintf_s_l etc do consider current thread's CRT locale somehow, but they do NOT do any thousand separator grouping right?

I try the code below:

int i1 = 7654321;
double d1 = 1234567.89;
char *locret = nullptr;

setvbuf(stdout, NULL, _IONBF, 0);

locret = setlocale(LC_ALL, "en-US");
assert(locret);
printf("en-US: %d | %.3f\n", i1, d1);

locret = setlocale(LC_ALL, "de-DE");
assert(locret);
printf("de-DE: %d | %.3f\n", i1, d1);

Compile the code in VS2019, I see that decimal point character varies with "en-US" and "de-DE". In Germany, people use comma as decimal point.

en-US: 7654321 | 1234567.890
de-DE: 7654321 | 1234567,890

But you see, thousand-grouping does NOT happen.

Snap1971 vs2019 CRT locale thousep no effect.png

From the lconv struct returned by localeconv(), there is information about grouping, .grouping=0x03. Looks like this .grouping info is never actually used by MSVCRT internally, instead, our application code has to digest this info and do grouping ourselves, right?

What I'd like to ask is: Does Microsoft ever provide any document listing which "locale properties" are actually implemented, and which are not?

If no such clear info is provided, I think we should avoid relying on those "culture" property provided by CRT-layer, instead, using another herd of locale functions from Winnls.h (WinAPI-layer) may be a better promise. For example, SetThreadLocale() sets/changes WinAPI-layer current thread-locale, then GetNumberFormat(), and we will see thousand separator applied.

==== Update ====

Well, now I get it. MSDN tolds it, but the wording is tricky.

Snap1973 LC_NUMERIC trick.png

The thousand separator character is only reflected in the lconv struct returned by localeconv(); it does not affect printf behavior. So, .grouping not affecting `printf' is unsurprising as well.


Solution

  • Q: MSVCRT printf never do thousand separator grouping, right?

    Right. There's an extension from the Single UNIX Specification which adds thousands' separators when the ' flag is provided. But this isn't implemented by MSVCRT.

    Q: Does Microsoft ever provide any document listing which "locale properties" are actually implemented, and which are not?

    Newer versions of MSVCRT strictly follow the C standard. The C11 standard says about setlocale:

    LC_COLLATE affects the behavior of the strcoll and strxfrm functions. LC_CTYPE affects the behavior of the character handling functions and the multibyte and wide character functions. LC_MONETARY affects the monetary formatting information returned by the localeconv function. LC_NUMERIC affects the decimal-point character for the formatted input/output functions and the string conversion functions, as well as the nonmonetary formatting information returned by the localeconv function. LC_TIME affects the behavior of the strftime and wcsftime functions.

    This is also spelled out in Microsoft's documentation of the setlocale function.

    Note that most of the information returned by localeconv (especially anything related to monetary values) is never used by any of the C library functions. This is by design. I think only decimal_point is actually used.