Wie speichere ich printf in einer Variablen?

Lesezeit: 4 Minuten

Benutzer-Avatar
Frank

Ich möchte eine formatierte Zeichenfolge mit etwas Ähnlichem wie printf in C speichern.

char *tmp = (char *)sqlite3_column_text(selectstmt, 2);
const char *sqlAnswers = printf("select key from answer WHERE key = %s LIMIT 5;", tmp);

Letzteres ist offensichtlich ein Fehler.

  • Einer der Gründe, warum es besser ist, Parameter zu binden

    – eckes

    8. Dezember 2017 um 17:33 Uhr

Benutzer-Avatar
Michael Ekstrand

Du kannst es mit machen sprintf, aber nicht allein (sicher). Verwenden Sie auf einem vernünftigen System snprintf zweimal, einmal, um die zu verwendende Größe herauszufinden, und das zweite Mal, um es tatsächlich zu tun. Dies hängt davon ab snprintf Gibt die Anzahl der benötigten Zeichen zurück, wenn der Platz knapp wird. Linux-, BSD- und C99-kompatible Systeme tun dies; Windows normalerweise nicht. Im letzteren Fall müssen Sie einen anfänglichen Puffer zuweisen und einen größeren zuweisen, wenn snprintf fehlschlägt (in einer Schleife bis snprintf gelingt es). Aber auf C99 funktioniert Folgendes:

char *buf;
size_t sz;
sz = snprintf(NULL, 0, "select key from answer WHERE key = %s LIMIT 5;", tmp);
buf = (char *)malloc(sz + 1); /* make sure you check for != NULL in real code */
snprintf(buf, sz+1, "select key from answer WHERE key = %s LIMIT 5;", tmp);

Jedochzum Erstellen von SQL, ist es viel besser zu verwenden vorbereitete Erklärungen. Sie vermeiden SQL-Injection-Schwachstellen (und häufig die Notwendigkeit von sprintf). Damit würden Sie die Anweisung „select key from answer where key = ? limit 5;“ vorbereiten und dann mit dem Parameter ausführen tmp. Die SQL-Engine fügt die Zeichenfolge ein und macht es überflüssig, zuerst sicherzustellen, dass sie richtig maskiert ist.

  • @Noldorin, kaum eine vorbereitete Aussage, Sie könnten temp immer noch ‘3;–drop table answer’ zuweisen.

    – Byron Whitlock

    17. November 2009 um 0:18 Uhr

  • Gesund, ein C99-Standard-konformes System zu sein! Einige C89-Implementierungen bieten ihre eigenen an snprintf das verhält sich nicht wie C99 beschreibt (Rückgabewert ist nicht unbedingt die benötigte Länge).

    – pmg

    17. November 2009 um 0:18 Uhr

  • +1 für die richtige Antwort, vorbereitete Aussagen, Puffersicherheit und die eine positive Bewertung, die Sie für 2000 Wiederholungen benötigten. Gern geschehen.

    – poundifdef

    17. November 2009 um 0:39 Uhr

  • @Byron Whitlock: Der Text für die vorgeschlagene ‘vorbereitete Erklärung’ war sicher gegen einen Schlüssel von ‘3;drop table answer;--‘ sowie Ihre Version des versuchten (aber fehlgeschlagenen) SQL-Injection-Angriffs.

    – Jonathan Leffler

    17. November 2009 um 3:12 Uhr

  • Ich habe eine kleine Korrektur vorgenommen, benutze (char *) im Malloc, um den Typ zu casten

    – Rodrigo

    17. September 2013 um 1:50 Uhr

Sie wollen sprintf().

char *sqlAnswers = malloc(SIZE_TO_HOLD_FINAL_STRING);
sprintf(sqlAnswers, "select key from answer WHERE key = %s LIMIT 5;", tmp);

  • Verwenden Sie immer snprintf() Zur sicherheit.

    – Greg Hewgill

    17. November 2009 um 0:10 Uhr

Wenn Sie gnu oder BSD libc verwenden, können Sie möglicherweise verwenden asprintfdie automatisch einen Puffer der richtigen Größe zuweist.

#define _GNU_SOURCE
#include <stdio.h>
// ...
char *sqlAnswers = NULL;
int length = asprintf(&sqlAnswers,"select key from answer WHERE key = %s LIMIT 5;", tmp);
free(sqlAnswers);

  • asprintf ist eine bequeme Abkürzung für die sprintf(malloc(snprintf(...))) Trick – ich stimme dafür, ihn zu verwenden und einen Fallback bereitzustellen asprintf Definition, wenn Sie sich jemals mit einer traurigen, veralteten Plattform auseinandersetzen müssen, der diese fehlt.

    – vergänglich

    17. November 2009 um 15:52 Uhr

Ich verwende tatsächlich sqlite3_bind_text, um meinen Platzhalter einzugeben, anstatt über sprintf zu generieren:

const char *sql1 = "select id, repA, key from iphone_reponse WHERE question_id = ?;";
sqlite3_stmt *selectstmt1;
if(sqlite3_prepare_v2(database, sql1, -1, &selectstmt1, NULL) == SQLITE_OK) {
    sqlite3_bind_text(selectstmt1, 1, [questionObj.key UTF8String], -1, SQLITE_TRANSIENT);

Benutzer-Avatar
Rodrigo

Das Michael Ekstrand Code ist gut, aber Sie müssen ihn mehrmals kopieren und einfügen. Ich verwende diesen Code in einer Funktion

char *storePrintf (const char *fmt, ...)
{
    va_list arg;
    va_start(arg, fmt);
    size_t sz = snprintf(NULL, 0, fmt, arg);
    char *buf = (char *)malloc(sz + 1);
    vsprintf(buf, fmt, arg);
    va_end (arg);
    return buf;
}

Hat es ein Problem mit Pufferüberlauf? Bis jetzt habe ich kein Problem damit.

Bearbeiten.

Ok, ich habe ein Problem, weil ich mit Arduino arbeite. Es verwendet Speicher und löscht es nicht, also müssen Sie es nach der Verwendung löschen.

Benutzer-Avatar
Wiederholung

Unter Windows können Sie sprintf_s verwenden, das einen Pufferüberlaufschutz hinzufügt, wie Michael E sagte.

http://msdn.microsoft.com/en-us/library/ce3zzk1k(VS.80).aspx

1312390cookie-checkWie speichere ich printf in einer Variablen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy