2009-11-17 11 views
14

quiero para almacenar una cadena con formato de usar algo similar a lo que hace printf en C.cómo almacenar printf en una variable?

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

Este último es, obviamente, un error.

+0

Una de las razones por las cuales es mejor vincular los parámetros – eckes

Respuesta

32

Puedes hacerlo con sprintf, pero no solo (con seguridad). En un sistema sano, use snprintf dos veces, una para averiguar el tamaño a usar y la segunda vez para hacerlo. Esto depende de snprintf devolviendo la cantidad de caracteres necesarios cuando se queda sin espacio. Los sistemas compatibles con Linux, BSD y C99 hacen esto; Windows normalmente no. En este último caso, deberá asignar un búfer inicial y asignar uno más grande si snprintf falla (en un bucle hasta que snprintf tenga éxito). Pero el C99, el siguiente trabajo:

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); 

Sin embargo, para la construcción de SQL, es mucho mejor usar prepared statements. Evitan las vulnerabilidades de inyección de SQL (y frecuentemente la necesidad de sprintf). Con ellos, prepararía la frase "seleccionar clave de respuesta donde clave =? Límite 5;" y luego ejecutarla con el parámetro tmp. El motor de SQL coloca la cadena y elimina la necesidad de asegurarse de que se haya escapado correctamente primero.

+2

+1 para declaraciones preparadas. – Noldorin

+0

@Noldorin, apenas una declaración preparada, aún se puede asignar '3; - drop table answer' a temp. –

+1

¡Siendo un sistema C99 estándar! Algunas implementaciones C89 ofrecen su propio 'snprintf' que no se comporta como lo describe C99 (el valor de retorno no es necesariamente la longitud requerida). – pmg

8

Quiere sprintf().

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

Siempre use 'snprintf()' para mayor seguridad. –

+1

Estoy de acuerdo con eso; +1. –

6

Si está utilizando gnu o BSD libc, puede utilizar asprintf, que asigna un búfer del tamaño correcto automáticamente.

#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); 
+4

'asprintf' es un atajo conveniente para el truco' sprintf (malloc (snprintf (...))) '- Yo voto por usar y proporcionando una definición 'asprintf' alternativa si alguna vez tiene que lidiar con una plataforma triste y obsoleta que no la tiene. – ephemient

0

En Windows puede usar sprintf_s que agrega protección de desbordamiento de búfer como decía Michael E.

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

+1

Parece que 'sprintf_s' no devuelve la cantidad de bytes necesarios si el buffer es demasiado pequeño; GNU y BSD 'snprintf' hacen ambas cosas. Ese era el comportamiento clave en el que estaba dependiendo. –

1

De hecho, estoy usando sqlite3_bind_text a la entrada de mi comodín en lugar de generar a través sprintf:

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); 
-1

El código Michael Ekstrand es bueno, pero se necesita copiar y pegar varios veces. Uso este código en una función

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; 
} 

¿Tiene problemas con el desbordamiento del búfer? Hasta ahora no tengo ningún problema con eso.

Editar.

Ok, tengo un problema porque estoy trabajando con Arduino. Utiliza memoria y no la deja caer, por lo que debe eliminarla después del uso.

Cuestiones relacionadas