2017-04-03 1 views
2

Sehr lange Zeichenfolge mit MyPrint() -Funktion wird abstürzen.vsnprintf gibt die Größe über die angegebene Puffergröße zurück

Ich dachte, dass vsnprintf() nicht die geschriebene Größe über die Pufferlänge von Linux Man Seite zurückgeben kann.

Meine erwartete Zeichenfolge ist abgeschnittene Zeichenfolge in Puffergröße, aber das ist völlig falsch von unter Testcode.

Was ist falsch unten ??

void myPrint(const char* fmt, ...) 
{ 
    char buffer[512] = {0,}; 

    va_list arg; 
    va_start(arg, fmt); 

    int r = vsnprintf(buffer, 511, fmt, arg); // buffer size is given 
    if (r > 0)    // works correctly 
     buffer[r+1] = '\0'; // crash because r is 200,000 
    va_end(arg); 
} 

int main(int, char**) 
{ 
    const char * data = "abcdefg...." // assuming that a length is 200,000 byte string 
    myPrint("%s\n", data); 
} 
+0

Sie müssen keine Zeichenfolge nach Gespräch zu beenden, 'vsnprintf' bereits das tut. – user694733

Antwort

6

Nein, die vsnprintf sehr speziell gibt die Anzahl der Zeichen für die vollständige Zeichenfolge erforderlich. C11 7.21.6.12p3:

vsnprintf Die Funktion, um die Anzahl der Zeichen zurückgibt, die geschrieben worden wäre, n ausreichend groß gewesen, nicht das abschließende Nullzeichen Zählen, oder einen negativen Wert, wenn ein Kodierungsfehler aufgetreten ist. Daher wurde die nullterminierte Ausgabe vollständig und genau dann geschrieben, wenn der zurückgegebene Wert nicht negativ ist und kleiner als n ist.

Zusätzlich sollte die Eingabegröße die volle Puffergröße sein, z. hier 512. Dann würde vsnprintf bis zu 511 Zeichen schreiben und die abschließende '\0' nach dem letzten geschriebenen Zeichen hinzufügen. (C11 snprintf description):

Andernfalls Ausgabezeichen über die n-1 eher verworfen als in das Array geschrieben werden, und ein Null-Zeichen ist am Ende der Zeichen geschrieben tatsächlich in das Array geschrieben. Wenn zwischen überlappenden Objekten kopiert wird, ist das Verhalten nicht definiert.

Zusätzlich ist zu beachten, dass (7.21.6.5p2):

[...] Somit wird die nullterminierte ausgegeben, wenn und nur vollständig geschrieben wurde, wenn der zurückgegebene Wert nicht negative und kleiner als n.

Das heißt, wenn Ihr Puffer ein Array von 512 char ist und Sie bestanden in 512 wurde die Zeichenfolge richtig geschrieben und nicht iff die Rückkehr n Wert von *snprintf abgeschnitten ist 0 <= n <= 511


Passen Sie auf, Microsoft Visual C++ hatte eine sehr defekte Funktion mit dem Namen _vsnprintf, die:

[...] die Anzahl der Zeichen wr wenn die Anzahl der zu schreibenden Zeichen kleiner oder gleich der Anzahl ist; Wenn die Anzahl der zu schreibenden Zeichen größer als die Anzahl ist, geben diese Funktionen -1 zurück und geben an, dass die Ausgabe abgeschnitten wurde.


Schließlich, wenn Sie nur Linux/Glibc spezifischen Code schreiben, können Sie auch mit vasprintf betrachten, die einen Puffer groß genug, um dynamisch zuweisen würde die gesamte Zeichenfolge zu halten.

+0

danke für deine ausführliche Erklärung !! – jay

+0

Beachten Sie, dass es zahlreiche andere alte Implementierungen der '* snprintf()' -Familie von Funktionen gibt, die bei der Ausgabeverkürzung ebenfalls '-1' zurückgegeben haben. Das war eine der zwei Hauptvarianten des Verhaltens, das vor der weit verbreiteten Standardisierung von C. existierte. –

+0

@AndrewHenle yeah, 'snprintf' ist C99 –

1

Es gibt mehrere Dinge zu beheben:

  1. Sie geben vollständige Puffergröße vsnprintf:

    int r = vsnprintf(buffer, sizeof buffer, fmt, arg); 
    
  2. Sie müssen keine Puffer nach Anruf beenden NUL. vsnprintf schneidet zu lange Zeichenfolge richtig ab.

  3. vsnprintf gibt die Länge zurück, die gewesen wäre, wenn die Kürzung nicht stattgefunden hätte. Wenn Sie Abschneiden erfassen müssen, können Sie es wie folgt tun:

    if(r >= sizeof buffer) { 
        // Buffer was too small  
    } 
    
+0

danke für Ihre Antwort !! – jay

Verwandte Themen