【问题标题】:Itoa and different character sets c++ visual studio 2013Itoa 和不同的字符集 c++ Visual Studio 2013
【发布时间】:2015-02-25 18:57:06
【问题描述】:

我的代码:

    m_ListCtrlCandidates.InsertItem(i, _itoa_s(candidate[i].ID, (char*)(LPCTSTR)str, 10));
    m_ListCtrlCandidates.SetItemText(i, 1, _itoa(candidate[i].FingerNumber, (char*)(LPCTSTR)str, 10));
    m_ListCtrlCandidates.SetItemText(i, 2, _itoa(candidate[i].SampleNumber, (char*)(LPCTSTR)str, 10));
    m_ListCtrlCandidates.SetItemText(i, 3, _itoa(candidate[i].ConfidenceLevel, (char*)(LPCTSTR)str, 10));

错误:

Error   2   error C4996: '_itoa': This function or variable may be unsafe. Consider using _itoa_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.    d:\documents\visual studio 2013\projects\gatekeeper\gatekeeper\gatekeeperdlg.cpp    416 1   Gatekeeper

我使用的 SDK 在其示例中包含以下代码。它将潜在匹配项添加到对话框中的列表中。最初,我将我的项目设置为 unicode 并更新了代码以使其正常工作。这给我带来了麻烦,所以我查看了示例代码,它的字符集是空白的。所以我改变了我的,现在我得到了这个错误。

如果我将它切换到 _itoa_s,我会收到函数不接受 3 个参数的错误。所以我想我错过了 size 参数,但我不确定它应该是什么大小。此外,当保留为 _itoa 时,它在他们的示例代码中编译得很好。

我真的很想将其保留为 Unicode。使用 _wtoi 而不是 atoi 在其他地方有所帮助。这个案例有类似的吗?

【问题讨论】:

    标签: unicode itoa


    【解决方案1】:

    我使用的 SDK 示例中包含以下代码。

    真不幸!

    _itoa(candidate[i].FingerNumber, (char*)(LPCTSTR)str, 10)

    我猜你正在使用 MFC,strCString,而你正在调用 CListCtrl::SetItemText

    CString 上的 (LPCTSTR) 运算符获取指向保存字符串数据的底层缓冲区的指针。这是一个const TCHAR*,所以如果你在ANSI模式下编译,这是一个指向字节的const char*指针;在 Unicode 模式下,它是一个 const wchar_t* 指向 16 位代码单元。

    将此转换为非常量 char* 并要求 _itoa 写信给它是一个非常糟糕的主意。这会覆盖最初在 CString 中的任何内容,如果数字足够大以至于生成的字符串比 CString 中的原始字符串长,您可能会写到数组的末尾,从而导致内存损坏严重。

    在 Unicode 模式下将其转换为 char* 更加奇怪,因为您使用 wchar_t 数组作为 char* 字节的存储空间。 Unicode 模式下的SetItemText() 肯定会期望得到wchar_t 字符吗?

    使用 _wtoi 而不是 atoi 在其他地方有所帮助。有没有类似的

    _itow 作为_itoawchar_t 类似物存在。 (至少在 VS 中。这两个函数都不是标准的 C[++]。)

    您可以打开#ifdef _UNICODE 并调用_itoa_itow 来匹配TCHAR 的类型。但是,除非您出于某些遗留原因确实需要支持仅古老的 ANSI 构建,否则现在没有太多理由为 TCHAR 切换而烦恼。您通常可以坚持使用 Unicode 模式并使用基于 wchar_t 的字符串作为文本。

    错误 C4996:“_itoa”:此函数或变量可能不安全。

    Microsoft 弃用了许多将可变数量的内容写入预分配缓冲区的 C 函数,因为缓冲区很容易太短,从而导致前面提到的内存损坏恐怖。过去,这已成为应用程序中无数安全问题的原因,因此最好避免。

    不幸的是,警告 4996 实际上弃用了一些并不真正危险的标准函数,这非常令人厌烦,尤其是其他编译器通常不支持建议作为替代的 _s 版本。

    在这种情况下,虽然 MS 有点正确,但_itoa 并不安全。为了安全地使用它,您必须为您要传递的类型的最长整数分配足够大的缓冲区,而且很容易出错。

    如果我将它切换到 _itoa_s,我会收到函数不接受 3 个参数的错误。所以我想我错过了 size 参数,但我不确定它应该是什么尺寸

    然而,在要写入的指针末尾有许多元素可用。因此,目前这将取决于您正在窃取其缓冲区的CString 的长度。但这样做并不是一个好主意。您可以分配自己的缓冲区:

    wchar_t str[8];
    _itow_s(candidate[i].FingerNumber, str, 8, 10);
    

    这是安全的,但如果 FingerNumber 的位数超过 7 位,它仍然会失败(带有 errno EINVAL),因为没有空间来存储它们(包括 \0 终止符)。

    itoa 这样将变量内容写入缓冲区的函数通常非常难看。如果您可以将现代 C++ 与 STL 一起使用,则可以使用更简单、更安全的字符串处理方法,例如:

    #include <string>
    
    std::wstring fingers = std::to_wstring(candidate[i].FingerNumber);
    m_ListCtrlCandidates.SetItemText(i, 1, fingers.c_str());
    

    (虽然这将如何与老式 MFC 和 CString 混合是另一个问题。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多