[英]snprintf vs. strcpy (etc.) in C
為了進行字符串連接,我一直在做 char* 緩沖區的基本strcpy
、 strncpy
。 然后我了解了snprintf
和朋友。
我應該堅持使用我的strcpy
, strcpy
+ \\0
終止嗎? 或者我將來應該只使用snprintf
嗎?
對於大多數目的,我懷疑使用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");
如果你想格式化你的字符串, snprintf 更健壯。 如果您只想連接,請使用 strncpy(不要使用 strcpy),因為它更有效。
正如其他人已經指出的那樣:不要使用 strncpy。
snprintf 將(在 POSIX 平台上)零終止。 在 Windows 上,只有 _snprintf,它不會以零終止,所以要考慮到這一點。
注意:當使用 snprintf 時,使用這種形式:
snprintf(buffer, sizeof(buffer), "%s", string);
代替
snprintf(buffer, sizeof(buffer), string);
后者是不安全的,並且 - 如果字符串取決於用戶輸入 - 可能導致堆棧粉碎等。
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
可用於將數字、指針值等格式化到緩沖區中。
所有 *printf 函數都檢查格式並擴展其相應的參數,因此它比簡單的 strcpy/strncpy 慢,后者僅從線性內存中復制給定數量的字節。
我的經驗法則是:
我認為 strncpy 和 snprintf 之間還有另一個區別。
想一想:
const int N=1000000;
char arr[N];
strncpy(arr, "abce", N);
通常,strncpy 會將目標緩沖區的其余部分設置為 '\\0'。 這將花費大量 CPU 時間。 而當你調用 snprintf 時,
snprintf(a, N, "%s", "abce");
它將保持緩沖區不變。
我不知道為什么 strncpy 會這樣做,但在這種情況下,我會選擇 snprintf 而不是 strncpy。
strcpy、strncpy 等只將字符串從一個內存位置復制到另一個內存位置。 但是,使用 snprint,你可以做更多的事情,比如格式化字符串。 將整數復制到緩沖區等。
這完全取決於您的要求使用哪一個。 如果按照您的邏輯,strcpy & strncpy 已經在為您工作,則無需跳轉到 snprintf。
另外,請記住按照其他人的建議使用 strncpy 以獲得更好的安全性。
strncpy 和 snprintf 之間的區別在於 strncpy 基本上由您負責用 '\\0' 終止字符串。 它可以用 '\\0' 終止 dst,但前提是 src 足夠短。
典型的例子是:
strncpy(dst, src, n);
// if src is longer than n dst will not contain null
// terminated string at this point
dst[n - 1] = '\0';
snprintf(dst, n, "%s", src); // dst will 100% contain null terminated string
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.