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