strcpy ... хотите заменить на strcpy_mine, который завершит работу strncpy и обнулится - PullRequest
6 голосов
/ 04 июня 2009

ключ в названии, но в основном я унаследовал некоторый код, который содержит более 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;
}

но размер всегда равен 4 pCopyMe - указатель

что я не хочу делать, это заменить

strcpy (buf, pCopyMe);

с

strncpy (buf, pCopyMe, sizeof(pCopyMe)); buf[sizeof(pCopyMe)] = 0;

есть идеи? (strcpy_l недоступен)

ура

Ответы [ 7 ]

11 голосов
/ 04 июня 2009

sizeof () возвращает размер типа - в этом случае const char* const, который будет равен 4 на 32-битных машинах.

Я думаю, вы думаете, что хотите strlen(). Но это не правильный способ использовать функции strncpy. Вам нужен размер буфера output для strncpy.

Чтобы это исправить, вам нужно изучить код на каждом сайте вызовов, определить размер выходного буфера и передать его в качестве аргумента strcpy_mine. Если сайт вызова для strcpy (или strcpy_mine) не знает размер выходного буфера, вам необходимо выполнить поиск в коде в обратном направлении для определения местоположения, которое выделяет буфер, и передать весь размер до сайта strcpy. .

По сути, вы не можете написать замену strcpy для замены, которая принимает те же аргументы и надеется избежать проблем, которые в первую очередь вызвали strncpy (и более качественные замены после этого). Вы можете создать функцию, которая принимает те же аргументы, что и strncpy, но гарантирует, что результат завершается нулем - посмотрите на реализацию функции strlcpy () OpenBSD. Но первым шагом должно быть изменение вызывающих сайтов для передачи информации о размере выходного буфера.

4 голосов
/ 04 июня 2009

В зависимости от того, как выглядят колл-сайты, часто большинство случаев может быть обработано простым шаблоном:

#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.

2 голосов
/ 04 июня 2009

Возможно, немного периферийно, но поскольку никто не упомянул об этом, и в заголовке это красуется: вы не можете (юридически) написать глобальную функцию с именем strcpy_mine().

«Пространство имен» функций, имена которых начинаются с str, зарезервировано для стандартной библиотеки. См., Например, принятый ответ на этот вопрос .

1 голос
/ 04 июня 2009

Вы можете использовать тот же список параметров, что и strncpy для вашего strcpy_mine, но записать его так, чтобы он всегда равнялся нулю, чтобы завершить результат. Не должно быть очень трудно сделать.

Однако одной из проблем является то, что часть вашего существующего кода, который вызывает strcpy (), может и не знать размер буфера.

0 голосов
/ 04 июня 2009

Дуглас Лидер правильно понял. Существует ограничение на полезность замены strcpy, если вы не готовы выполнять основную работу по передаче хорошей, разумной длины буфера в каждом конкретном случае. Это много работы!

Хорошая новость в том, что оно того стоит! Несколько лет назад я участвовал в нескольких проектах C ++, которые были запоздалыми, с ошибками и ненадежными. Объявив strcpy и strlen запрещенными и потратив 2-3 дня на проект, чтобы заменить их на пользовательские strncpy / strnlen, во всех этих проектах мы неожиданно могли работать в течение нескольких дней вместо часов. Мы также видели много усеченных строк, появляющихся на экранах и в файлах журналов. Это дало нам подсказки, необходимые для отслеживания проблем с усечением, которые раньше вызывали сбои.

Если вы не хотите этого делать, вы можете получить гораздо меньшее преимущество, просто проверив оба параметра указателя на NULL, и ограничив максимальный размер копии строки и ведя журнал все время, когда граница достигнута. Не делайте strlen ни с одним из параметров, так как strlen с радостью вылетит на вас, если строка неправильно обнуляется.

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

0 голосов
/ 04 июня 2009

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

Это не по теме, но я просто хочу отметить, что после использования strncpy() вам нужно установить в ноль последний символ буфера, индекс которого 1 меньше чем длина (не длина буфера):

strncpy (buf, pCopyMe, buflen); buf[buflen - 1] = '\0';

Или, в качестве альтернативы, вы можете использовать strncat() для пустой строки, передавая ей длину, которая на 1 меньше, и это гарантирует нулевое завершение вашей строки:

buf[0] = '\0'; strncat (buf, pCopyMe, buflen - 1);
0 голосов
/ 04 июня 2009

Также Вы можете использовать макросы для избежания многократного редактирования. Или автоматизировать редактирование с помощью какого-либо скрипта.

...