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 недоступен)

ваше здоровье


person timB33    schedule 04.06.2009    source источник


Ответы (7)


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

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

person Suma    schedule 04.06.2009
comment
ваше здоровье! это почти то, что мне нужно, но это все равно заставляет меня указывать размер буфера в шевронах, хотя char buf[200]; strcpy_mine‹200›(buf, pString); - person timB33; 05.06.2009
comment
strCpyMine‹sizeof(buf)›(buf, pString); - person timB33; 05.06.2009
comment
Устаревший компилятор Я думаю, я использую VC6; см. support.microsoft.com/kb/165803. - person timB33; 05.06.2009
comment
Я делал что-то не так. Шаблон должен быть немного другим. Исправление сейчас. - person Suma; 05.06.2009

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

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

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

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

person Douglas Leeder    schedule 04.06.2009
comment
+1 за strlcpy. При написании моей собственной функции, подобной этой, я также передаю перечисление {AllOrNothing, TruncateOkay} в функцию, чтобы она обрабатывала случаи переполнения. - person Dolphin; 04.06.2009

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

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

person unwind    schedule 04.06.2009

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

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

person Fred Larson    schedule 04.06.2009
comment
Я поддерживаю это. Вам нужно будет добавить еще один параметр для размера выходного буфера. Метод strcpy является классическим источником ошибок переполнения буфера. Microsoft даже отказалась от этой функции в пользу чего-то вроде strncpy. - person Mark; 04.06.2009

Также Вы можете использовать макросы, чтобы избежать многократных правок. Или автоматизировать редактирование через какой-нибудь скрипт.

person vitaly.v.ch    schedule 04.06.2009
comment
Если вам интересно, макрос в единственном числе, макрос во множественном числе. Макросы - это не слово. Я предполагаю, что английский не является вашим родным языком. Я только пытаюсь тебе помочь. - person jmucchiello; 27.10.2009

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

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

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

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

buf[0] = '\0'; strncat (buf, pCopyMe, buflen - 1);
person newacct    schedule 04.06.2009
comment
если вы все равно этим занимаетесь, почему бы и нет: strncpy(buf, pCopyMe, buflen)[buflen-1]='\0'; :-) - person AndersK; 05.06.2009

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

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

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

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

person kmarsh    schedule 04.06.2009