Setting C++ locale for 1 category

S

Stephen Howe

Hi

I believe that if I do

std::locale::global(std::locale("C"));

that now only does change the global C++ locale but it also passes
through to the C locale as if I had done

setlocale(LC_ALL, "C");

But in C I can do

setlocale(LC_CTYPE, ".1252");

Now exactly how is done in C++?
One of C++'s locale constructors is

locale(const locale& other, const char *name, category cat);

but I am not interested in other, I am interested in name and
category.
How do I set the global locale but just for LC_CTYPE alone?

Thanks

Stephen howe
 
N

Nobody

How do I set the global locale but just for LC_CTYPE alone?

std::locale::global(std::locale(std::locale(), "C", std::locale::ctype));

This sets the C++ global locale, but I don't know if it's guaranteed to
set the C locale. It works with g++ on Linux, where std::locale().name()
returns a string of the form "LC_CTYPE=C;LC_NUMERIC=en_GB;...".

It's probably safe to assume that it won't work if you construct a locale
by mixing and matching facets rather than categories.
 
S

Stephen Howe

std::locale::global(std::locale(std::locale(), "C", std::locale::ctype));

This sets the C++ global locale, but I don't know if it's guaranteed to
set the C locale.

I have since learnt:
It is if a name is present ("C").
If a name is given it then does

setlocale(LC_ALL, loc.name.c_str());

So that means the standard is causing an all-category set.
This looks like a flaw in the C++ standard.

Stephen Howe
 
N

Nobody

I have since learnt:
It is if a name is present ("C").
If a name is given it then does

setlocale(LC_ALL, loc.name.c_str());

So that means the standard is causing an all-category set.
Correct.

This looks like a flaw in the C++ standard.

It isn't. Well, "flaw" is a bit ambiguous, but the problem which I think
that you're implying doesn't exist.

If the current locale happens to be the C locale, then the result of:

std::locale(std::locale(), "C", std::locale::ctype)

will actually be the C locale, as you're taking the LC_CTYPE category from
the C locale and the other categories from the C locale also. The
implementation recognises this and gives the resulting locale the name
"C". So there's no error in the resulting locale having the name "C", nor
in std::locale::global calling setlocale(LC_ALL, "C").

Even if you construct a "heterogeneous" locale by combining categories
from different locales, there's no problem with std::locale::global
calling setlocale(LC_ALL, ...), provided that the complete locale can be
described by a string which is acceptable to setlocale().

Bear in mind that the C standard says:

7.11.1.1 The setlocale function

Synopsis

[#1]

#include <locale.h>
char *setlocale(int category, const char *locale);

Description

...

[#7] A null pointer for locale causes the setlocale function
to return a pointer to the string associated with the
category for the program's current locale; the program's
locale is not changed.175)

[#8] The pointer to string returned by the setlocale
function is such that a subsequent call with that string
value and its associated category will restore that part of
the program's locale. The string pointed to shall not be
modified by the program, but may be overwritten by a
subsequent call to the setlocale function.

...

175The implementation shall arrange to encode in a string
the various categories due to a heterogeneous locale when
category has the value LC_ALL.

So, if you create a heterogeneous locale by way of multiple setlocale()
calls with different categories, setlocale(LC_ALL, NULL) must return a
string such that setlocale(LC_ALL, str) will restore that locale.

It only becomes tricky if you want to mix your own setlocale() calls with
calls to std::locale::global(). The latter calls the former (where
possible), but the former doesn't touch the C++ global locale. The
construction which I gave earlier changes a single category of the C++
locale, then updates the C locale to match it.

Provided that the C and C++ locales were previously "in sync", the effect
is "as if" setlocale() had been called for a single category; it updates
all categories, but only one of them actually differs from its previous
setting. If the C and C++ locales were out of sync, the call will
resynchronise them. You might consider that a flaw; I consider it a case
of "don't do that".

I think (but don't know for certain) that it should suffice to use:

std::locale::global(std::locale(setlocale(LC_ALL, NULL)));

to synchronise the C++ locale to the C locale, in the event that the two
have become desynchronised by explicit setlocale() calls.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,756
Messages
2,569,540
Members
45,025
Latest member
KetoRushACVFitness

Latest Threads

Top