strcpy… хочу заменить на strcpy_mine, который завершится с помощью strncpy и null
Вопрос
подсказка содержится в заголовке, но по сути я унаследовал некоторый код, который имеет более 800 экземпляров strcpy.Я хочу написать новую функцию, а затем заменить strcpy на strcpy_mine.
Итак, я пытаюсь выяснить, какой список параметров будет иметь strcpy_mine.
Я пытался:
void strcpy_mine( char* pTarget, const char* const pCopyMe )
{
const unsigned int lenAlwaysFour = sizeof(pCopyMe ); //:(
strncpy( pTarget, pCopyMe, lenAlwaysFour );
//add extra terminator in case of overrun
pTarget[lenAlwaysFour] = 0;
}
но sizeof всегда равен 4. pCopyMe — это указатель
чего я не хочу делать, так это заменять
strcpy (buf, pCopyMe);
с
strncpy (buf, pCopyMe, sizeof(pCopyMe)); buf[sizeof(pCopyMe)] = 0;
Любые идеи?(strcpy_l недоступен)
ваше здоровье
Решение
В зависимости от того, как выглядят сайты вызовов, зачастую большинство случаев можно решить с помощью простого шаблона:
#include <string.h>
template <int bufferSize>
void strcpy_mine( char (&pTarget)[bufferSize], const char* const pCopyMe )
{
strncpy( pTarget, pCopyMe, bufferSize-1 );
//add extra terminator in case of overrun
pTarget[bufferSize-1] = 0;
}
int main()
{
char buf[128];
strcpy_mine(buf,"Testing");
return 0;
}
Если вы используете Microsoft Visual Studio 2005 или новее, см. Безопасные перегрузки шаблонов для реализации Microsoft.
Другие советы
sizeof() возвращает размер типа – в данном случае const char* const
который будет равен 4 на 32-битных машинах.
Я думаю, ты думаешь, что хочешь strlen()
.Но это неправильный способ использования функций strncpy.Вам нужен размер выход буфер для strncpy.
Чтобы это исправить, вам нужно изучить код на каждом месте вызова, определить размер выходного буфера и передать его в качестве аргумента strcpy_mine
.Если сайт вызова для strcpy (или strcpy_mine) не знает размер выходного буфера, вам нужно выполнить поиск в обратном направлении в коде места, которое выделяет буфер, и передать размер полностью на сайт strcpy. .
По сути, вы не можете написать замену для strcpy, которая принимает те же аргументы и надеется избежать проблем, которые изначально вызвали strncpy (и более эффективные замены).Вы можете создать функцию, которая принимает те же аргументы, что и strncpy, но гарантирует, что результат завершается нулем — посмотрите на реализацию Функция strlcpy() OpenBSD функция.Но первым шагом должно быть изменение вызывающих сайтов, чтобы они передавали информацию о размере выходного буфера.
Немного второстепенно, возможно, но поскольку об этом никто не упомянул и оно красуется в названии:вы не можете (юридически) написать глобальную функцию с именем strcpy_mine()
.
«Пространство имен» функций, имена которых начинаются с str
зарезервирован для стандартной библиотеки.См., например, принятый ответ на этот вопрос.
Вы можете использовать тот же список параметров, что и strncpy, для вашего strcpy_mine, но напишите его так, чтобы он всегда завершал результат нулевым значением.Это не должно быть очень сложно сделать.
Однако одна из проблем заключается в том, что часть вашего существующего кода, вызывающего strcpy(), также может не знать размер буфера.
Также Вы можете использовать макросы, чтобы избежать многократного редактирования.Или автоматизировать редактирование с помощью какого-нибудь скрипта.
Вам обязательно нужно передать размер целевого буфера в качестве параметра, как уже говорили другие люди.
Это немного не по теме, но я просто хочу отметить, что после использования strncpy()
, вам нужно обнулить последний символ буфера, который имеет индекс на 1 меньше чем длина (не длина буфера):
strncpy (buf, pCopyMe, buflen); buf[buflen - 1] = '\0';
Или, альтернативно, вы можете использовать strncat()
в пустой строке, передав ей длину на 1 меньше, и это гарантирует нулевое завершение вашей строки:
buf[0] = '\0'; strncat (buf, pCopyMe, buflen - 1);
Дуглас Лидер прав.Существует предел полезности замены strcpy, если только вы не готовы выполнять тяжелую работу по передаче хорошей, разумной длины буфера в каждом экземпляре.Это много работы!
Хорошая новость в том, что оно того стоит!Несколько лет назад я столкнулся с несколькими проектами C++, которые были запоздалыми, содержали ошибки и были ненадежными.Объявив strcpy и strlen запрещенными и выделив 2-3 дня из проекта, чтобы заменить их пользовательскими strncpy/strnlen, во всех этих проектах мы внезапно смогли работать днями, а не часами.Мы также видели множество обрезанных строк на экранах и в файлах журналов.Это дало нам подсказки, необходимые для отслеживания проблем с усечением, прежде чем возникали проблемы со сбоями.
Если вы не хотите этого делать, вы можете получить гораздо меньшую выгоду, просто проверив оба параметра указателя на NULL и ограничив максимальный размер копии строки и регистрация всех случаев достижения границы. Не выполняйте strlen для любого параметра, так как strlen с радостью приведет к сбою, если строка не будет правильно завершена нулем.
В настоящее время в новых проектах используются хорошие строковые объекты, но существует множество устаревшего кода, который этого не делает.