2013-10-05 114 views
0

根據我對C標準的閱讀,如果snprinf在寫入時達到maxlen,它將返回一個正數或負數(它實際上並不清晰),其大小與未寫入的字符數相等。該規範還表示,該函數將返回任何錯誤的負值。所以我的問題是:這是什麼返回在以下兩種情況下...如果maxlen> 0時什麼都不寫,snprintf會返回什麼結果?

Maxlen > 0,發生前一個錯誤,snprintf撈出

Maxlen > 0沒有寫入字符,所有字符都寫,錯誤某種發生和snprintf保釋金

我知道最後一個,特別是不太可能。但我想更好地理解規範。在我看來,snprintf的返回使得你是否正確地寫了一部分字符串不明確。

        • 編輯

顯然這是不明確。讓我詳細說明一下:

*>哪個負數不重要。錯誤是一個錯誤,它不是

事情發生之前寫入了多少字節。 這可能是大多數人的實際案例。我看到snprintf應該返回多餘的字符數,但是,我想知道是否可以使用該值。 對我來說,這個規範似乎很奇怪,它會經歷報道有用的事情的麻煩,只是讓它不清楚它是否真的返回了一些不相關的東西。這沒有意義嗎? 我想知道是否還有更多的是使我們能夠確定的snprintf失敗,因爲它被賦予了太多的輸入習慣。*

我現在就買下。我發現截斷以外的任何錯誤都是負數,成功爲0 < R < = maxsize,截斷爲0 < maxsize < R.謝謝大家的回覆。

+0

「如果輸出由於此限制而被截斷,則返回值是字符數(不包括結束空值如果有足夠的空間可用,它將被寫入最終的字符串。「什麼含糊不清? – Kevin

+0

您在我的問題中間沒有閱讀這兩行。 – SaburoutaMishima

+1

我做了,而且我還不確定爲什麼你感到困惑。 – Kevin

回答

1

我想知道是否有更多的約定,使得有可能確定是否snprintf失敗,因爲它被給予太多的輸入。

這很簡單。對於錯誤,返回負數。對於截斷,返回數字> =大小。無論您是否考慮截斷錯誤,您都會測試這兩個條件並按照您認爲合適的方式進行處理。

+0

我不得不多次重讀該規範,直到找到我想要的東西。我認爲在你重讀關於輸出大小的行之前,你所說的有問題。當然,沒有辦法將成功的運行與截斷相混淆,因爲成功的返回值至多是大小。我沒有想到這一點,所以我認爲截斷被認爲是一個錯誤,並返回一個負值。 – SaburoutaMishima

+0

對你的評論稍作修改。成功返回值*小於*'大小'。 'size' count包含終止空值,但返回值只返回字符輸出,不包括終止空值。 –

+0

哦,謝謝。我沒有注意到規模和回報的差異。 – SaburoutaMishima

0

man page的描述:

返回值

在成功返回,這些函數返回打印的字符的數目(不包括用於結束輸出爲字符串的空字節)。

函數snprintf()和vsnprintf()不會寫入多於大小的字節(包括終止空字節('\ 0'))。如果輸出由於此限制而被截斷,則返回值是在足夠空間可用的情況下將被寫入最終字符串的字符數(不包括終止空字節)。因此,大小或更大的返回值意味着輸出被截斷。 (另請參閱下面的註釋)

如果遇到輸出錯誤,則返回負值。

因此,對於你的情況:

Maxlen > 0,發生錯誤之前沒有字符寫入和snprintf撈出

snprintf返回負數。哪個負數不重要。

Maxlen > 0,所有字符都寫,會發生某種錯誤,snprintf的保釋金

snprintf返回負數。哪個負數不重要。錯誤是一個錯誤,它在發生之前寫入了多少字節並不重要。

2

這不是我讀標準的方法。從n1570草案(最終免費的,我認爲):

的snprintf的函數返回會 被寫入了ň已經足夠大,不計算 終止空字符的字符數,或負號如果發生了編碼錯誤 ,則返回值。因此,當且僅當返回值非負且小於n時,空終止輸出才被完全寫入 。

他們的原型是:

int sprintf(char * restrict s, const char * restrict format, ...); 

...所以他們的 「n」 是大概你的 「MAXLEN」 值。

所以,沒有問題。如果有錯誤,你會得到-42或其他任意的負數。如果沒有,你會得到所有要寫入的數據的長度。擬合的部分被寫入緩衝區,如果返回值大於或等於n,則會出現截斷。

我看到的唯一未指定的位是nsize_t,所以結果可能會大於適合正整型返回值的值。不過,我想不出一個會受此影響的應用程序。

+0

我已經接受了答案,但我認爲這實際上是最清晰的陳述。謝謝。 – SaburoutaMishima

0

作爲進一步的評論,使用的snprintf時反覆逐步建立一個字符串(例如,在一個循環中) - 或任何地方必須確定結果字符串的長度,我建議這是一個「安全」的方法...

int foo(char * b, size_t bLen) { 
    size_t sLen = 0; 
    for(int i = 0; i < 1000; i++) { 
    int res = snprintf(&b[sLen], bLen - sLen, "%d. A string ", sLen); 
    // sLen:   Inc by +ive res,  (upto safe maximum)   
    sLen = std::min(sLen + (res>0?res:0), (bLen?bLen-1:bLen)); 
    } 
    return sLen; 
} 

所述的snprintf後的線將安全遞增字符串長度可變(SLEN),忽略陰性結果(RES)和通過限制到緩衝長度(BLEN)防範溢出。 在我的例子中,我使用了C++「min」,但是堆棧溢出提供了'C'選項:MIN and MAX in C