2009-01-12 12 views
12

Kennt jemand eine gute sichere Möglichkeit, die Ausgabe einer printf-style-Funktion auf eine Zeichenfolge umzuleiten? Die offensichtlichen Wege führen zu Pufferüberläufen.Der beste Weg, um sicher auf eine Zeichenkette zu drucken?

Etwas wie:

string s; 
output.beginRedirect(s); // redirect output to s 

... output.print("%s%d", foo, bar); 

output.endRedirect(); 

ich glaube, das Problem ist das gleiche wie die Frage, „wie viele Zeichen produzieren gedruckt werden?“ Ideen?

Antwort

4

This StackOverflow question eine ähnliche Diskussion hat. Auch in dieser Frage stelle ich meine Lieblingslösung vor, eine "Format" -Funktion, die printf identische Argumente entgegennimmt und eine std :: string zurückgibt.

0

Microsoft führen Sie die 'safe' CRT-Funktionen dafür ein.

Sie könnten printf_s()

+2

Nicht verfügbar auf anderen Standards konforme Implementierung, so yuck. – Bklyn

+0

Der einzige Unterschied besteht darin, dass der "sichere" CRT selbst abstürzt, wenn er bestimmte undefinierte Verhaltensweisen erkennt. Das umgeht nicht das Problem, dem er begegnet. –

11

Die snprintf() Funktion druckt auf eine Zeichenfolge verwenden, aber nur so viel wie die Länge gegeben.

Könnte das sein, was Sie suchen ...

+0

Schneller als ich. Das ist der alte Weg, es zu tun. – dmckee

+0

Sie können sprintf verwenden, für das keine Länge erforderlich ist. Auch das wird nicht mit Strings funktionieren, als er fragte ... –

+1

@abyx - spot on! Es wäre gut, ein Beispiel für std :: string hinzuzufügen, z. snprintf (Ziel, SIZE, "% s% d", foo.c_str(), Balken); – orip

24

können Sie verwenden:

std::snprintf wenn Sie mit einem char arbeiten *

std::stringstream wenn Sie Zeichenfolgen verwenden möchten (nicht gleiche als printf, ermöglicht es Ihnen jedoch, den String mit den normalen Stream-Funktionen zu bearbeiten.

boost::format wenn Sie eine Funktion ähnlich printf wollen, die mit Streams arbeiten wird. (nach jalf in Kommentaren)

+2

und boost :: format vermeidet, um printf-ähnliche Formatierungsfähigkeiten mit C++ - Streams zu erhalten – jalf

1

Mit C99 haben Sie die snprintf-Funktion, die die Größe des Puffers als Parameter annimmt. Die GNU C-Bibliothek hat asprintf, die einen Puffer für Sie reserviert. Für C++ ist es jedoch besser, iostream zu verwenden.

Wikipedia hat weitere Informationen.

4

Alte Schule:

snprintf() 

können Sie eine Begrenzung der Zahl geschrieben bringen, und geben die tatsächliche geschrieben Größe und

asprintf() 

zuweisen (mit malloc()) einen ausreichenden Puffer, der dann wird Ihr Problem zu free(). `asprintf ist eine GNU libc-Funktion, die jetzt in der BSD libc erneut implementiert wird.

6

Da Sie dies als C++ gekennzeichnet haben (und nicht nur C), werde ich darauf hinweisen, dass die typische Vorgehensweise in C++ stringstream ist, nicht die printf-Familie. Sie müssen sich keine Gedanken über Pufferüberläufe mit Stringstreams machen.

Die Bibliothek Boost Format ist auch verfügbar, wenn Sie Druckformat-Zeichenketten bevorzugen, aber etwas Sichereres wollen.

+0

+1 für Boost-Format (schlagt mich dazu :) – orip

3

snprintf() gibt die Anzahl der Bytes zurück, die zum Schreiben der gesamten Zeichenfolge benötigt werden.So , als kleines Beispiel:

#include <strings.h> 
#include <stdio.h> 
#include <stdlib.h> 

int main(int argc, char** argv) 
{ 
    char* buf = 0; 
    size_t bufsize = 0; 
    size_t sz; 

    const char* format="%s and %s."; 
    const char* str_1 ="string 1"; 
    const char* str_2 ="string 2"; 

    sz = snprintf(buf, bufsize, format, str_1, str_2); 
    printf("The buffer needs to be %d bytes.\n", sz); 

    buf=malloc(sz+1); 
    if(!buf) { 
     printf("Can't allocate buffer!\n"); 
     return 1; 
    } 
    bufsize = sz+1; 
    buf[bufsize-1] = '\0'; 
    sz = snprintf(buf, bufsize, format, str_1, str_2); 
    printf("Filled buffer with %d bytes.\n", sz); 
    printf("The buffer contains:\n'%s'\n", buf); 
    return 0; 
} 

Ausgang:

The buffer needs to be 22 bytes. 
Filled buffer with 22 bytes. 
The buffer contains: 
'string 1 and string 2.' 
0

Unter Windows:

StringCchPrintf 
StringCbPrintf 

von strsafe.h/lib.

1

Ich finde die Printf-Formatierung sehr hilfreich und einfacher zu verwenden als Streams. Auf der anderen Seite mag ich auch std :: string. Die Lösung besteht darin, sprintf zu verwenden, aber das kann nicht mit beliebiger Puffergröße umgehen.

Ich habe festgestellt, dass ich häufige Fall behandeln muss (sagen wir, Puffer begrenzt auf 256 Zeichen) ohne Overhead, und doch den großen Puffer sicher handhaben. Um dies zu tun, habe ich einen Puffer von 256 Zeichen in meiner Klasse als Mitglied zugeordnet, und ich benutze snprinf, übergibt diesen Puffer und seine Größe. Wenn snprintf erfolgreich ist, kann ich die formatierte Zeichenfolge sofort erneut senden. Wenn es fehlschlägt, ordne ich den Puffer zu und rufe snprinf erneut auf. Der Puffer wird im Destruktor der Klasse freigegeben.

3

The fmt library bietet fmt::sprintf Funktion, die printf-kompatible Formatierung (nach POSIX specification einschließlich Positionsargumente) führt und gibt das Ergebnis als std::string:

std::string s = fmt::sprintf("%s%d", foo, bar); 

Haftungsausschluss: Ich bin der Autor dieser Bibliothek.

Verwandte Themen