Итоа и разные наборы символов C++ visual studio 2013

Мой код:

    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 аргумента. Поэтому я предполагаю, что мне не хватает аргумента размера, но я не уверен, какой он должен быть. Кроме того, он прекрасно компилируется в их примере кода, если оставить его как _itoa.

Я бы очень хотел сохранить его в Unicode. Использование _wtoi вместо atoi помогло в других местах. Есть ли что-то подобное для этого случая?

1 ответ

Решение

Я использую SDK, который имеет следующий код в их примере.

Это прискорбно!

_itoa (кандидат [я]. ФингерНомер, (символ *)(LPCTSTR) ул., 10)

Я предполагаю, что вы используете MFC, str это CStringи ты звонишь CListCtrl::SetItemText,

(LPCTSTR) оператор на CString получает указатель на базовый буфер, содержащий строковые данные. Это const TCHAR*, так что если вы компилируете в режиме ANSI, это const char* указатель на байты; в режиме Юникод это 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 переключение в эти дни. Вы можете просто придерживаться режима Юникод и использовать wchar_tстроки для текста.

ошибка C4996: '_itoa': эта функция или переменная может быть небезопасной.

Microsoft отказалась от ряда функций C, которые записывают переменные объемы содержимого в заранее выделенные буферы, потому что буферы могут быть слишком короткими, что приводит к вышеупомянутому ужасу повреждения памяти. В прошлом это было причиной множества проблем с безопасностью в приложениях, поэтому лучше избегать этого.

К сожалению, предупреждение 4996 фактически не поддерживает некоторые стандартные функции, которые тоже не очень опасны, что довольно утомительно, особенно если учесть, что _s версии, предлагаемые в качестве замены, обычно не поддерживаются другими компиляторами.

В этом случае, хотя MS вроде как, _itoa не совсем безопасно. Чтобы использовать его безопасно, вам нужно выделить достаточно большой буфер для максимально длинного целого числа передаваемого вами типа, и это действительно легко сделать неправильно.

Если я переключаю его на _itoa_s, я получаю ошибку, что функция не принимает 3 аргумента. Итак, я предполагаю, что мне не хватает аргумента размера, но я не уверен, какой размер он должен быть

Однако в конце указателя доступно множество элементов для записи. Так что в настоящее время это будет зависеть от длины CString чей буфер ты крадешь. Но это не очень хорошая идея. Вы можете выделить свой собственный буфер:

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

Это безопасно, хотя все равно не удается (с ошибкой EINVAL) если FingerNumber имеет более 7 цифр, так как не было бы места для их хранения (включая \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 - другой вопрос.)

Другие вопросы по тегам