当使用 _ENABLE_PER_THREAD_LOCALE 时,STL 对象使用 C 运行时库语言环境进行浮点转换?

发布于 2024-10-01 18:00:19 字数 1614 浏览 1 评论 0原文

C 运行时语言环境由 setlocale 设置。 标准 C++ 库 (STL) 区域设置由 std::locale 类设置,并且可以在单个 STL 对象(例如 std::istringstream 等)上设置。

函数 _configthreadlocale(_ENABLE_PER_THREAD_LOCALE) code> 允许在每个线程的基础上设置 C 运行时区域设置。

不幸的是,启用 _configthreadlocale(_ENABLE_PER_THREAD_LOCALE) 的线程中的 STL 对象似乎正在使用 C 运行时区域设置。或者至少使用 C 运行时语言环境的小数点。

在没有 _ENABLE_PER_THREAD_LOCALE 的线程中,没有问题。

Paavo 在 2008 年提出了类似的问题,但没有答案:_configthreadlocale 和 localeconv

下面的代码显示了问题:

//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  

有没有人经历过这个前?我做错了什么吗?有解决方案的建议吗?

提前致谢 /TEB

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

不必在意 2024-10-08 18:00:19

由于 C++ 标准库最近才获得有关线程的知识,因此这种明显的二分法并不令我感到惊讶。对不同场景中发生的情况进行了详尽的讨论(特定于 Microsoft,但作为一般背景似乎很有帮助)这里

总之:

使用 C++ 更改区域设置
运行时库,使用 locale 类。
通过调用 locale::global 方法,
您更改每个线程中的区域设置
尚未明确启用
每个线程的区域设置。要改变
单个线程或部分中的区域设置
的应用程序,只需创建一个
其中的语言环境对象的实例
线程或部分代码。

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.

蹲墙角沉默 2024-10-08 18:00:19

免责声明:我不是语言环境专家,因此这可能是错误的。

关于多线程和区域设置知识库文章指出:

调用 locale::global 会改变
标准 C++ 的语言环境
库和 C 运行时库。
但是,仅调用 setlocale
更改 C 运行时的区域设置
图书馆;标准 C++ 库是
不受影响。

您确实正在使用 C++ 标准库,因此在我看来您需要调用 locale::global()。当我这样做时,返回值正如你所期望的那样。这是我的示例代码:

#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  
}

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  
}
挽手叙旧 2024-10-08 18:00:19

约翰·迪布林说得好。我已经测试过了,运算符>>值确实使用流中的区域设置,而不是全局区域设置。它通过以下示例进行了测试:

_configthreadlocale(_ENABLE_PER_THREAD_LOCALE),已删除
locale::global(locale("dan​​ish"));,添加以设置全局 Std lib 区域设置

#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  
}

我猜到目前为止的结论是启用 _configthreadlocale(_ENABLE_PER_THREAD_LOCALE) 的线程中的 STL 对象确实使用 C 运行时区域设置。

可以通过使用 locale::global() 调用设置 Std lib 语言环境和 C 运行时语言环境来解决此问题。但由于 Std lib 区域设置不是线程安全的,并且不受 _ENABLE_PER_THREAD_LOCALE 的影响,因此我们仍然可以通过此解决方法遇到多线程问题。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文