1

The C Runtime locale is set by setlocale. The Standard C++ Library (STL) locale is set by the std::locale class and can be set on individual STL objects like std::istringstream etc.

The function _configthreadlocale(_ENABLE_PER_THREAD_LOCALE) allows setting the C Runtime locale on a per thread basis.

Unfortunately it seems that STL objects in threads where _configthreadlocale(_ENABLE_PER_THREAD_LOCALE) is enabled is using the C Runtime locale. Or at least using the decimal point of the C Runtime locale.

In threads without _ENABLE_PER_THREAD_LOCALE there are no problems.

Something similar was asked by Paavo in 2008, but with no answers: _configthreadlocale and localeconv

The following code shows the problem:

//Enable per thread locale in current thread  
_configthreadlocale(_ENABLE_PER_THREAD_LOCALE)  

//Create istringstream object  
std::istringstream LibraryStream;  
//Create double object  
double Value = 0;  
//Create std::locale object with "C" locale ("." as decimal point)  
std::locale StreamLoc("C");  
//Set C Runtime locale to danish ("," as decimal point)  
setlocale(LC_ALL, "danish");  

//Set the "C" locale on the istringstream object  
LibraryStream.imbue(StreamLoc);  
//Get the locale of the istringstream object for test (returns "C" as expected)  
std::locale NewStreamLoc = LibraryStream.getloc();  

//Set floating point string with "C" locale decimal point in istringstream object  
LibraryStream.str("60.258351");  
//Convert the string to double  
LibraryStream >> Value;  

//Now the expected value of "Value" is 60.258351, but it is 60.000  
//when debugging the conversion, I can see that "," is used as decimal point  

Have anyone experienced this before? Am I doing something wrong? Are there any suggestions for solutions?

Thanks in advance /TEB

Community
  • 1
  • 1
TEB
  • 11
  • 3
  • Welcome to SO. When posting code samples, you can use the little `101101` button above the edit field to get the code formatted properly. – Björn Pollex Nov 10 '10 at 14:56

3 Answers3

3

Since C++ Standard Library only recently gained knowledge of threads, this apparent dichotomy does not surprise me. There is an exhaustive discussion of what happens in different scenarios (Microsoft-specific, but seems to be helpful as general background) here.

In summary:

To change the locale using the C++ Runtime Library, use the locale Class. By calling the locale::global method, you change the locale in every thread that has not explicitly enabled per-thread locale. To change the locale in a single thread or portion of an application, simply create an instance of a locale object in that thread or portion of code.

Steve Townsend
  • 53,498
  • 9
  • 91
  • 140
1

Disclaimer: I am not an expert at locales, so this may be wrong.

On the Multithreading and Locales Knowlegde Base article it is noted:

Calling locale::global changes the locale for both the Standard C++ Library and the C Runtime Library. However, calling setlocale only changes the locale for the C Runtime Library; the Standard C++ Library is not affected.

You are indeed using the C++ Std Lib, so it seemed to me that you needed to call locale::global(). When I did this, the return value is as you expected. Here is my sample code:

#include <cstdlib>
#include <locale>
#include <sstream>
using namespace std;

int main()
{

    //Enable per thread locale in current thread  
    int n = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE)  ;

    //Create istringstream object  
    std::istringstream LibraryStream;  
    //Create double object  
    double Value = 0;  
    //Create std::locale object with "C" locale ("." as decimal point)  
    std::locale StreamLoc("C");  
    //Set C Runtime locale to danish ("," as decimal point)  
    char* ret = setlocale(LC_ALL, "danish");  

    //Set the "C" locale on the istringstream object  
    LibraryStream.imbue(StreamLoc);  
    locale::global(StreamLoc);
    //Get the locale of the istringstream object for test (returns "C" as expected)  
    std::locale NewStreamLoc = LibraryStream.getloc();  

    //Set floating point string with "C" locale decimal point in istringstream object  
    LibraryStream.str("60.258351");  
    //Convert the string to double  
    LibraryStream >> Value;  

        //Now the expected value of "Value" is 60.258351, but it is 60.000  
    //when debugging the conversion, I can see that "," is used as decimal point  
}
John Dibling
  • 99,718
  • 31
  • 186
  • 324
  • Yes you are right that calling locale::global() will change the locale for both the Standard C++ Library and the C Runtime Library. – TEB Nov 10 '10 at 19:15
  • However I would like to keep the locale for the C Runtime Library and only use the locale on the specific STL object (istringstream LibraryStram) using the imbue() method. – TEB Nov 10 '10 at 19:18
  • Does `operator>> Value` use the locale in the stream, or the global locale? – John Dibling Nov 10 '10 at 19:47
0

Good point John Dibling. I have tested that and the operator>> Value does use the locale in the stream and not the global locale. It was tested by the example below:

_configthreadlocale(_ENABLE_PER_THREAD_LOCALE), removed
locale::global(locale("danish"));, added to set the global Std lib locale

#include <cstdlib>
#include <locale>
#include <sstream>
using namespace std;

int main()
{
    //Enable per thread locale in current thread  
    //int n = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE)  ;

    //Create istringstream object  
    std::istringstream LibraryStream;  
    //Create double object  
    double Value = 0;  
    //Create std::locale object with "C" locale ("." as decimal point)  
    std::locale StreamLoc("C");  
    //Set C Runtime locale to danish ("," as decimal point)  
    char* ret = setlocale(LC_ALL, "danish");

    //Set Std lib global locale to "danish"
    locale::global(locale("danish"));

    //Set the "C" locale on the istringstream object  
    LibraryStream.imbue(StreamLoc);  

    //Get the locale of the istringstream object for test (returns "C" as expected)  
    std::locale NewStreamLoc = LibraryStream.getloc();  

    //Set floating point string with "C" locale decimal point in istringstream object  
    LibraryStream.str("60.258351");  
    //Convert the string to double  
    LibraryStream >> Value;  

    //In this case the value of "Value" is 60.258351, as expected and thus  
    //the "C" locale was use for conversion  
}

I guess the conclusion so far is that STL objects in threads where _configthreadlocale(_ENABLE_PER_THREAD_LOCALE) is enabled is indeed using the C Runtime locale.

It is possible to work around this by setting both the Std lib locale and the C Runtime locale with the locale::global() call. But as Std lib locale is not thread safe and not affected by the _ENABLE_PER_THREAD_LOCALE, we can still run in to multithreading problems with this workaround.

TEB
  • 11
  • 3