0

我的代码:

    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 在其他地方有所帮助。这种情况有类似的东西吗?

4

1 回答 1

2

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

那真不幸!

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

我猜你正在使用 MFC,str是一个CString,你正在调用CListCtrl::SetItemText.

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

将它转换为非常量char*并要求_itoa写入它是一个非常糟糕的主意。这会覆盖原来在 中的任何内容CString,如果数字足够大以至于结果字符串比原来在 中的字符串长,那么CString您可能会在数组末尾写入,从而导致内存损坏破坏。

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

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

_itow作为 的wchar_t类似物存在_itoa。(至少在 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);

这是安全的,尽管EINVAL如果 FingerNumber 有超过 7 位数字,它仍然会失败(使用 errno ),因为没有空间来存储它们(包括\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 混合是另一个问题。)

于 2015-02-25T22:39:51.377 回答