无论区域设置如何,如何将浮点数转换为字符串?

时间:2009-02-03 15:10:04

标签: c++ mfc formatting locale

我的产品面向葡萄牙观众,逗号为十进制符号。我通常使用CString :: Format将数字输入字符串,并考虑计算机的区域设置。虽然这通常是一种很好的方法,但我在格式化SQL查询方面遇到了问题,例如:

CString szInsert;
szInsert.Format("INSERT INTO Vertices (X, Y) VALUES (%f, %f)", pt.X, pt.Y);

当传递值时,我得到这个不正确的查询字符串:

INSERT INTO Vertices (X, Y) VALUES (3,56, 4,67)

如何在这些字符串中强制使用点作为小数点符号,而不更改区域设置,也不必为每个浮点值设置专门的字符串?

注意:这是一般性问题,而不是SQL问题。

5 个答案:

答案 0 :(得分:10)

不好的想法,你真的应该使用预备语句。使用数字进行SQL注入并不是一件容易的事,但CString :: Format不是执行参数绑定的正确方法。

(MFC和SQL已经有一段时间了 - 结果证明这是血腥的隐藏。我开始看到我们最终得到了SQL注入错误,感谢Microsoft。使用原始ODBC,您可以使用SQLPrepare创建一个语句(一次) 。传递?为你要填写的2个参数。随后,对于每个INSERT调用SQLBindParameter(stmt, 1, &X); SQLBindParameter(stmt, 2, &Y) /*extra parameters omitted, see http://msdn.microsoft.com/en-us/library/ms710963(VS.85).aspx */。最后,调用SQLExecute来执行操作。)

答案 1 :(得分:9)

关于使用ostringstream的Pukku建议的评论:为了使这个独立于语言环境,人们应该明确地使用所需的语言环境灌输():

std::ostringstream s;
s.imbue(std::locale::classic());
s << "INSERT INTO Vertices (X, Y) VALUES (" << pt.X << ", " << pt.Y << ")";

否则,使用当前的全局语言环境。

答案 2 :(得分:6)

参数化查询应该完全避免这个问题。你应该研究那些。也就是说,您应该能够使用setlocale或类似的更改小数分隔符。

答案 3 :(得分:1)

这就是我的所作所为。

CString FormatQuery(LPCTSTR pszFormat, ...)
{
    CString szLocale = setlocale(LC_NUMERIC, NULL);
    setlocale(LC_NUMERIC, "English");

    va_list args;
    va_start(args, pszFormat);
    CString szFormatted;
    int nSize = (_vscprintf(pszFormat, args) + 1) * sizeof(char);
    _vsnprintf_s(szFormatted.GetBuffer(nSize), nSize, nSize, pszFormat, args);
    szFormatted.ReleaseBuffer();
    va_end(args);

    setlocale(LC_NUMERIC, szLocale);
    return szFormatted;
}

您应该像sprintf一样使用它。您必须#include <locale.h>才能使其正常工作。

我有点顽固所以我没有使用预备语句/参数化查询。如果你有类似的问题,我建议你这样做。同时,如果您的问题与SQL无关,我的回答应该有所帮助。

编辑:这是一个线程安全版本:

CString FormatQuery(LPCTSTR pszFormat, ...)
{
    _locale_t locale = _create_locale(LC_NUMERIC, "English");

    va_list args;
    va_start(args, pszFormat);
    CString szFormatted;
    int nSize = (_vscprintf_l(pszFormat, locale, args) + 1) * sizeof(char);
    _vsnprintf_s_l(szFormatted.GetBuffer(nSize), nSize, nSize, pszFormat, locale, args);
    szFormatted.ReleaseBuffer();
    va_end(args);

    return szFormatted;
}

答案 4 :(得分:1)

使用

_create_locale( LC_NUMERIC, "C" )

创建一个&#39;英语&#39; (默认为C语言环境),然后将其传递给_sprintf_l函数组之一。

e.g。

_locale_t locale = _create_locale( LC_NUMERIC, "C" );
_sprintf_l( pszValue, "%f", locale, 3.141 );
_free_locale(locale);

这是线程安全的。语言环境可以存储在静态变量中,以避免每次需要格式化值时创建它。