strcpy… хочу заменить на strcpy_mine, который завершится с помощью strncpy и null

StackOverflow https://stackoverflow.com/questions/951119

  •  11-09-2019
  •  | 
  •  

Вопрос

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top