簡體   English   中英

C 中的 snprintf 與 strcpy(等)

[英]snprintf vs. strcpy (etc.) in C

為了進行字符串連接,我一直在做 char* 緩沖區的基本strcpystrncpy 然后我了解了snprintf和朋友。

我應該堅持使用我的strcpy , strcpy + \\0終止嗎? 或者我將來應該只使用snprintf嗎?

對於大多數目的,我懷疑使用strncpysnprintf之間的區別是可衡量的。

如果涉及任何格式,我傾向於只使用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。

  • strncpy 在截斷的情況下不會零終止。
  • 如果字符串比緩沖區短,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 慢,后者僅從線性內存中復制給定數量的字節。

我的經驗法則是:

  • 需要格式化時使用 snprintf。
  • 當只需要復制一塊線性內存時,堅持使用 strncpy/memcpy。
  • 只要您確切地知道要復制的緩沖區的大小,就可以使用 strcpy 。 如果您不能完全控制緩沖區大小,請不要使用它。

我認為 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM