printf 的浮点格式标志 (%f) 仅适用于英文数字格式
Posted
技术标签:
【中文标题】printf 的浮点格式标志 (%f) 仅适用于英文数字格式【英文标题】:printf's floating point format flag (%f) for English number format only 【发布时间】:2018-02-24 22:45:01 【问题描述】:我正在将数据写入一个可以在多台计算机上打开的文件。问题是,当我使用“%f”格式化标志格式化浮点数时,函数的printf
变体(wprintf
、CString::Format
、StringCchPrintf
等)使其成为特定于语言环境的变量。
例如:
double f = 1.5;
WCHAR buff[256];
StringCchPrintf(buff, 256, L"%f", f);
将为美国英语输出"1.5"
,但随后可能为某些欧洲语言环境等输出"1,5"
。
所以我很好奇除了%f
之外是否还有一个标志只会以一种格式输出浮点数? (最好是英文。)
【问题讨论】:
不,没有。 @NeilButterworth:那你是做什么的?编写您自己的从浮点到字符串的转换例程,或者在每次printf
调用之前更改和恢复语言环境?
编写一个包装 printf 的函数,它可以透明地更改和恢复语言环境。或者在程序开始时更改一次区域设置。
【参考方案1】:
考虑到这个问题被标记为 C++:使用 std::num_put
和 std::numpunct
中的格式设置为 ”C”
语言环境。最简单的方法是使用合适的std::ostream
和imbue()
ing std::locale::classic()
。
评论建议编写自己的转换函数:我建议不要这样做,因为正确实现此转换并非易事。见How to Print Floating-Point Numbers Accurately。
【讨论】:
如果您指的是我的评论,我不建议重写 printf,正如您所说的那样,这将是一项重大任务,我建议将其包装以管理语言环境的更改。 @NeilButterworth:MikeF 询问“编写你自己的从浮点到字符串的转换例程”。【参考方案2】:您需要在致电StringCchPrintf
或说_snwprintf
之前致电setlocale
或_wsetlocale
。例如:
WCHAR buf[32];
double f = 1.5;
setlocale(LC_NUMERIC, "english");
_snwprintf(buf, RTL_NUMBER_OF(buf), L"%f", f);
// 1.500000
setlocale(LC_NUMERIC, "German");
_snwprintf(buf, RTL_NUMBER_OF(buf), L"%f", f);
// 1,500000
或者作为替代可以使用StringCchPrintf_l
或其他_l函数。但在这种情况下,您需要致电 _create_locale
和 _free_locale
WCHAR buf[32];
double f = 1.5;
_locale_t locale;
if (locale = _create_locale(LC_NUMERIC, "German"))
_snwprintf_l(buf, RTL_NUMBER_OF(buf), L"%f", locale, f);
_free_locale(locale);
// 1,500000
if (locale = _create_locale(LC_NUMERIC, "english"))
_snwprintf_l(buf, RTL_NUMBER_OF(buf), L"%f", locale, f);
_free_locale(locale);
// 1.500000
我们可以使用例如下一个Language Strings。但是存在多种使用语言环境字符串的方法
【讨论】:
setlocale
(默认情况下)为进程中的所有线程设置区域设置,从而更改不属于您的线程的运行时行为。 SetThreadLocale 是一个更好的选择。或者,使用_configthreadlocale 启用每线程区域设置。
@IInspectable - 或者我们可以通过_create_locale
创建语言环境并明确使用它,就像我在代码中显示的那样
我在评论您提出的第一个解决方案,它不太理想,并且会引入微妙的(而不是那么微妙的)错误。如果您必须更改语言环境,则仅对调用线程执行此操作。根本不改变语言环境通常是一个更好的主意。但是,仅显示第二个解决方案并不能解决第一个解决方案的问题。
@IInspectable - 这取决于 - 哪个代码调用 setlocale
。如果来自 exe 的代码 - 这没关系。 exe代码有权这样做。如果来自通用 dll - 这已经不行了,并且真的会影响进程。
这也不能从 EXE 调用。它改变了你不拥有或控制的线程的环境。我已经解释了问题是什么,并提出了两种解决方法。【参考方案3】:
在程序中尝试以下操作:
setlocale (LC_ALL, "en_US.UTF-8");
或者在程序启动前设置环境变量:
export LC_NUMERIC="en_US.UTF-8";
【讨论】:
以上是关于printf 的浮点格式标志 (%f) 仅适用于英文数字格式的主要内容,如果未能解决你的问题,请参考以下文章