и snprintf, и и strcpy (и т. д.) in C

для выполнения конкатенации строк я делаю basic strcpy, strncpy буферов char*. Затем я узнал о snprintf и друзей.

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

7 ответов


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

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

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

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");

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


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

мое эмпирическое правило:

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

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 возвращает количество символов, которые он написал в буфер, поэтому продвижение вашего буфера на столько позиций оставит вас указывающим на '' В конце то, что было написано до сих пор. Поэтому, когда вы передаете обновленную позицию следующему sprintf, он может начать писать новые символы справа там.

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

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

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


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

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

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

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

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

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

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


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

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

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


Как делали другие точки уже вышла: не используйте функції strncpy.

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

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

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

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

вместо

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

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