Anything still wrong is probably wrong for good....

by Michael S. Kaplan, published on 2009/07/13 10:16 -04:00, original URI:

Some complaints people have had about the doc story on some international issues have been around for a long time.

Longer than this Blog in some cases.

Now this Blog (and the constituent blogs thereof) has been around since the end of 2004. So if I point an issue that was first mentioned by readers here in a blog like What is my locale? Well, which locale do you mean? that was first published on February 1, 2005, then it is clear that this is an issue that been around for a bit.

Maybe a whole byte's worth of bits. Or more....

The simple truth:

setlocale(LC_ALL, "")

will set all aspects of the default CRT locale to be the same as the user default locale, aka LOCALE_USER_DEFAULT.

You can tell me if that sounds confusing or not.

I'm pretty sure it is less confusing than phrases like you can find in the various versions of the MSDN docs about setlocale, _wsetlocale.

Generally, no one gets it right.

Ben Bryant pointed out in a comment to that very blog about how the Delphi 7 SysUtils got this one wrong; not sure if they managed to fix this up or not.

Now in theory you can try to make clever use of ".ACP" or ".OCP" to try and fix^H^H^Hwork around this, but if you want to be sure to completely get the correct locale, code like this will show you a properly set CRT locale:

#define _UNICODE
#define UNICODE
#include <tchar.h>
#include <stdio.h>
#include <locale.h>
#include <windows.h>

#define SIZE(x) (sizeof(x) / sizeof(x[0]))

void _tmain() {
    TCHAR language[80] = {0};
    TCHAR country[80] = {0};
    TCHAR codepage[5] = {0};
    TCHAR localestring[167] = {0};

        GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_SENGLANGUAGE, language, SIZE(language)) &&
        GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_SENGCOUNTRY, country, SIZE(country)) &&
        GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE, codepage, SIZE(codepage)) && // use LOCALE_IDEFAULTCODEPAGE for console apps
        (_stprintf_s(localestring, SIZE(localestring), _T("%s_%s.%s"), language, country, codepage) >= 0)
      ) {
        _tprintf(_T("NULL     --> %s\n"), _tsetlocale(LC_ALL, NULL));
        _tprintf(_T("To set   --> %s\n"), localestring);
        _tprintf(_T("Set \"\"   --> %s\n"), _tsetlocale(LC_ALL, _T("")));
        _tprintf(_T("Set sys  --> %s\n"), _tsetlocale(LC_CTYPE, localestring));
        _tprintf(_T("NULL     --> %s\n"), _tsetlocale(LC_ALL, NULL));
    } else {
        _tprintf(_T("%s\n"), _T("Error!"));

Note it also handles a few other problems like the fact that the setlocale, _wsetlocale docs make no mention to the _tsetlocale function that works quite well, thank you.

The code basically sets the user locale for everything, then sets the system locale for LC_CTYPE -- which handles the character property stuff (that is actually locale independent, ref: ) and the codepage stuff so that all non-Unicode operations will use the same default that the system does.

And although using ".ACP" or ".OCP" will return comparable results, any querying of the LC_CTYPE locale won't match the system, which is why I like this code better -- it gives correct answers. :-)

Anyway, I have given up on trying to see this topic fixed in MSDN. It has slowly been getting better but to be honest way too slowly to be helpful. And no one wants to "fix" the function since people will have behavior differences to deal with if "" wrre to suddenly really mean "act like the system does", which is what the above settings would do.

So I thought I'd write this blog....

Tyler on 14 Jul 2009 7:05 PM:

the setlocale stuff is terrifying enough that I have stopped using the CRT for anything remotely locale sensitive.

Please consider a donation to keep this archive running, maintained and free of advertising.
Donate €20 or more to receive an offline copy of the whole archive including all images.

referenced by

2010/01/19 You down with .OCP (Yeah you know me!)

go to newer or older post, or back to index or month or day