我是一个库的开发人员,我们的旧代码使用sscanf()和sprintf()从/到字符串读/写各种内部类型.我们遇到过使用我们库的用户的问题,并且其语言环境与我们基于XML文件的语言环境不同("C"语言环境).在我们的例子中,这导致从这些XML文件解析的值不正确,以及在运行时以字符串形式提交的值.区域设置可以由用户直接更改,但也可以在用户不知情的情况下进行更改.如果区域设置更改发生在另一个库中,例如GTK,这是一个错误报告中的"犯罪者",就会发生这种情况.因此,我们显然希望从语言环境中删除任何依赖关系,以永久地摆脱这些问题.
我已经在float/double/int /的上下文中阅读了其他问题和答案,特别是如果它们被一个字符分隔或位于括号内,但到目前为止,我发现的建议解决方案并不令我们满意.我们的要求是:
除了标准库之外,不依赖于库.因此,使用boost中的任何内容都不是一种选择.
必须是线程安全的.这具体涉及可以全局更改的区域设置.这对我们来说真的很糟糕,因为我们库的一个线程可能会受到用户程序中另一个线程的影响,该线程也可能正在运行一个完全不同的库的代码.setlocale()因此,任何直接受影响的东西都不是一种选择.此外,由于线程中的竞争条件,在开始读/写之前设置区域设置并将其设置回原始值不是解决方案.
虽然效率不是最重要的优先级(#1和#2),但它仍然是我们关注的问题,因为字符串可能会在运行时频繁地读取和写入,具体取决于用户的程序.越快越好.
编辑:作为补充说明:boost::lexical_cast不保证不受语言环境的影响(来源:boost :: lexical_cast <>的语言环境不变保证).即使没有要求#1,这也不是解决方案.
到目前为止,我收集了以下信息:
std::to_string,std::stod,std::stof,等取决于全球区域只是sscanf的方式和sprintf做的,这是非常不幸的,我不理解的,考虑到的std ::螺纹已被添加.std::stringstream似乎是一般的解决方案,因为它在语言环境的上下文中是线程安全的,但一般来说如果保护正确的话.但是,如果它每次都是新建的,那么它很慢(良好的比较:http://www.boost.org/doc/libs/1_55_0/doc/html/boost_lexical_cast/performance.html).我假设这可以通过配置和使用每个线程一个这样的流来解决,每次使用后清除它.但是,问题在于它不能像以下那样容易地解决格式sscanf(),例如:" { %g , %g } ".sscanf() 例如,我们需要能够阅读的模式是:
" { %g , %g }"" { { %g , %g } , { %g , %g } }"" { top: { %g , %g } …是否有计划添加在当前语言环境下不变的 C 标准库字符串处理函数版本?
目前有很多脆弱的解决方法,例如,来自 jansson/strconv.c:
static void to_locale(strbuffer_t *strbuffer)
{
const char *point;
char *pos;
point = localeconv()->decimal_point;
if(*point == '.') {
/* No conversion needed */
return;
}
pos = strchr(strbuffer->value, '.');
if(pos)
*pos = *point;
}
static void from_locale(char *buffer)
{
const char *point;
char *pos;
point = localeconv()->decimal_point;
if(*point == '.') {
/* No conversion needed */
return;
}
pos = strchr(buffer, *point);
if(pos)
*pos = '.';
}
Run Code Online (Sandbox Code Playgroud)
这些函数预处理它的输入,以便它可以独立于当前语言环境使用,在假设下
setlocale在这些修复函数和对任何受影响函数的调用之间没有调用(1) 意味着预处理方法在异国语言环境中中断(参见https://en.wikipedia.org/wiki/Decimal_mark#Hindu.E2.80.93Arabic_numeral_system示例)。(2) …