snprintf против strcpy (и т. д.) в C - PullRequest
6 голосов
/ 09 апреля 2010

Для выполнения конкатенации строк я делал базовые strcpy, strncpy буферов char *. Потом я узнал о snprintf и друзьях.

Должен ли я придерживаться терминации strcpy, strcpy + \0? Или я должен просто использовать snprintf в будущем?

Ответы [ 7 ]

7 голосов
/ 09 апреля 2010

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

Если есть какое-либо форматирование, я склонен придерживаться только snprintf, а не смешивать в strncpy.

Я считаю, что это помогает ясности кода и означает, что вы можете использовать следующую идиому, чтобы отслеживать, где вы находитесь в буфере (таким образом, избегая создания алгоритма Shlemiel the Painter ):

char sBuffer[iBufferSize];
char* pCursor = sBuffer;

pCursor += snprintf(pCursor, sizeof(sBuffer) - (pCursor - sBuffer),  "some stuff\n");

for(int i = 0; i < 10; i++)
{
   pCursor += snprintf(pCursor, sizeof(sBuffer) - (pCursor - sBuffer),  " iter %d\n", i);
}

pCursor += snprintf(pCursor, sizeof(sBuffer) - (pCursor - sBuffer),  "into a string\n");
6 голосов
/ 09 апреля 2010

snprintf более надежен, если вы хотите отформатировать вашу строку. Если вы хотите только объединить, используйте strncpy (не используйте strcpy), так как это более эффективно.

3 голосов
/ 09 апреля 2010

sprintf имеет чрезвычайно полезное возвращаемое значение, которое позволяет эффективно добавлять.

Вот идиома:

char buffer[HUGE] = {0}; 
char *end_of_string = &buffer[0];
end_of_string += sprintf( /* whatever */ );
end_of_string += sprintf( /* whatever */ );
end_of_string += sprintf( /* whatever */ );

Вы поняли идею. Это работает, потому что sprintf возвращает количество символов, которые он записал в буфер, поэтому продвижение вашего буфера на столько позиций оставит вас указывать на '\0' в конце того, что было написано до сих пор. Поэтому, когда вы передаете обновленную позицию следующей sprintf, она может сразу же начать писать новые символы.

Сравните с strcpy, возвращаемое значение которого должно быть бесполезным. Он возвращает вам тот же аргумент, что и вы. Таким образом, добавление с strcpy подразумевает обход всей первой строки в поисках конца. И затем добавление снова с другим вызовом strcpy подразумевает обход всей первой строки, за которой следует вторая строка, которая теперь живет после нее, в поисках '\0'. Третий strcpy будет перебирать строки, которые уже были записаны снова. И так далее.

Таким образом, для многих небольших добавлений к очень большому буферу strcpy приближается (O ^ n), где n - количество добавлений. Что ужасно

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

3 голосов
/ 09 апреля 2010

Все * функции printf проверяют форматирование и расширяют соответствующий ему аргумент, поэтому он медленнее простого strcpy / strncpy, который копирует только определенное количество байтов из линейной памяти.

Мое правило:

  • Используйте snprintf всякий раз, когда необходимо форматирование.
  • Придерживайтесь strncpy / memcpy, когда нужно скопировать только блок линейной памяти.
  • Вы можете использовать strcpy, когда точно знаете размер копируемых буферов. Не используйте это, если у вас нет полного контроля над размером буферов.
2 голосов
/ 22 марта 2012

Я думаю, что есть еще одна разница между strncpy и snprintf.

Подумайте об этом:

const int N=1000000;
char arr[N];
strncpy(arr, "abce", N);

Обычно strncpy устанавливает остаток целевого буфера в '\ 0'. Это будет стоить много процессорного времени. Когда вы звоните snprintf,

snprintf(a, N, "%s", "abce");

оставит буфер без изменений.

Я не знаю, почему strncpy сделает это, но в этом случае я выберу snprintf вместо strncpy.

1 голос
/ 10 апреля 2015

Как уже отмечали другие: не используйте strncpy.

  • strncpy не обнуляется в случае усечения.
  • strncpy обнуляет весь буфер, если строка короче буфера. Если буфер большой, это может привести к снижению производительности.

snprintf будет (на платформах POSIX) завершаться нулем. В Windows есть только _snprintf, который не будет заканчиваться нулем, так что примите это во внимание.

Примечание: при использовании snprintf используйте эту форму:

snprintf(buffer, sizeof(buffer), "%s", string);

вместо

snprintf(buffer, sizeof(buffer), string);

Последнее небезопасно и - если строка зависит от пользовательского ввода - может привести к перебоям в стеке и т. Д.

1 голос
/ 09 апреля 2010

strcpy, strncpy и т. Д. Копирует только строки из одной ячейки памяти в другую.Но с помощью snprint вы можете делать больше вещей, например форматировать строку.Копирование целых чисел в буфер и т. Д.

Это зависит только от вашего требования, какой из них использовать.Если по вашей логике strcpy & strncpy уже работает для вас, вам не нужно переходить к snprintf.

Также не забывайте использовать strncpy для большей безопасности, как это предлагают другие.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...