2009-11-17 7 views
14

나는 후자는 분명히 오류가 발생 C.printf를 변수에 저장하는 방법은 무엇입니까?

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

을 무엇 printf와 유사한을 사용하여 포맷 된 문자열을 저장할.

+0

매개 변수를 바인딩하는 것이 더 좋은 이유 중 하나 – eckes

답변

32

sprintf으로 할 수 있지만 (안전하게) 혼자서 할 수는 없습니다. 정상적인 시스템에서는 snprintf을 두 번 사용하십시오. 한 번 사용할 크기를 확인하고 실제로 두 번 눌러 확인하십시오. 이는 방이 다되었을 때 필요한 문자 수를 반환하는 snprintf에 달려 있습니다. Linux, BSD 및 C99 호환 시스템에서이 작업을 수행합니다. Windows는 일반적으로 그렇지 않습니다. 후자의 경우, snprintf이 실패하면 (초기 루프를 snprintf이 성공할 때까지) 초기 버퍼를 할당하고 더 큰 버퍼를 할당해야합니다. 그러나 C99에서 다음 작동합니다 :

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

그러나는 SQL을 구축, 그것은 prepared statements를 사용하는 것이 훨씬 낫다. SQL 인젝션 취약점을 피할 수 있습니다 (자주 sprintf 필요). 그 (것)들과 함께, 당신은 진술서 "대답으로부터 키 선택 where key =? limit 5;"를 준비하고, tmp 매개 변수로 그것을 실행합니다. SQL 엔진은 문자열을 넣고 제대로 이스케이프 처리되었는지 확인해야합니다.

+2

+1. – Noldorin

+0

@ Noldorin, 준비된 진술은 아니지만 임시 테이블에 '3 드롭 테이블 응답'을 지정할 수 있습니다. –

+1

Sane은 C99 표준을 준수하는 시스템입니다! 일부 C89 구현은 C99이 설명하는 것처럼 동작하지 않는 자체 snprintf를 제공합니다 (반환 값은 반드시 필요한 길이는 아닙니다). – pmg

8

당신은 sprintf()을 원합니다.

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

안전을 위해 항상'snprintf()'를 사용하십시오. –

+1

나는 그것에 동의 할 수있다; +1. 준비된 진술에 대해서는 –

6

gnu 또는 BSD libc를 사용하는 경우 올바른 크기의 버퍼를 자동으로 할당하는 asprintf을 사용할 수 있습니다.

#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'는'sprintf (malloc (snprintf (...))) '트릭의 편리한 바로 가기입니다. 그걸 가지고 있지 않은 슬픈 구식 플랫폼을 다뤄야 만한다면'asprintf' 정의를 제공 할 수 있습니다. – ephemient

0

windows에서는 sprintf_s를 사용하여 Michael E가 말한 것처럼 버퍼 오버 플로우 방지 기능을 추가 할 수 있습니다. 실제로 입력에 내 와일드 카드를 sqlite3_bind_text를 사용하는 대신에 sprintf를 통해 생성하고

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

+1

'sprintf_s'는 버퍼가 너무 작 으면 필요한 바이트 수를 반환하지 않습니다. GNU와 BSD의'snprintf' 둘 다 그렇습니다. 그것은 내가 의존하고 있던 중요한 행동이었습니다. –

1

:

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

마이클 Ekstrand 코드는 좋다, 그러나 당신은 복사하고 다양한 붙여 넣기해야합니다 타임스. 하나의 함수에서이 코드를 사용합니다.

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

버퍼 오버 플로우에 문제가 있습니까? 지금까지는 문제가 없습니다.

편집.

좋아, 나는 Arduino와 일하고 있기 때문에 문제가있다. 메모리를 사용하고 삭제하지 않으므로 사용 후 삭제해야합니다.

관련 문제