如何将printf存储到一个变量中?

时间:2022-12-27 15:46:01

I want to store a formatted string using something similar to what printf does in C.

我希望使用类似于printf在C中的操作来存储格式化字符串。

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

The latter is an error obviously.

后者显然是一个错误。

6 个解决方案

#1


34  

You can do it with sprintf, but not alone (safely). On a sane system, use snprintf twice, once to find out the size to use and the second time to actually do it. This depends on snprintf returning the number of characters needed when it runs out of room. Linux, BSD, and C99-compatible systems do this; Windows typically does not. In the latter case, you'll need to allocate an initial buffer and allocate a bigger one if snprintf fails (in a loop until snprintf succeeds). But on C99, the following will work:

你可以用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);

However, for building SQL, it's far better to use prepared statements. They avoid SQL injection vulnerabilities (and frequently the need for sprintf). With them, you would prepare the statement "select key from answer where key = ? limit 5;", and then execute it with the parameter tmp. The SQL engine puts in the string and removes the need to make sure it's properly escaped first.

但是,对于构建SQL,最好使用准备好的语句。它们避免了SQL注入漏洞(并且经常需要sprintf)。使用它们,您将准备语句“select key from answer where key = ?”限制5;,然后使用参数tmp执行它。SQL引擎输入字符串,并消除了确保它首先正确转义的需要。

#2


8  

You want sprintf().

你想要sprintf()。

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

#3


6  

If you're using gnu or BSD libc you may be able to use asprintf, which allocates a buffer of the correct size automatically.

如果您正在使用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


1  

I am actually using sqlite3_bind_text to input my wildcard instead of generating through sprintf:

我实际上是在使用sqlite3_bind_text输入我的通配符,而不是通过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);

#5


0  

On windows you can use sprintf_s which adds buffer overflow protection like Michael E was saying.

在windows上,您可以使用sprintf_s来添加缓冲区溢出保护,就像Michael E所说的那样。

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

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

#6


-1  

The Michael Ekstrand code is good, but you will need to copy and paste it various times. I use this code in one function

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

Does it has problem with buffer overflow? Until now I don't have problem with it.

是否存在缓冲区溢出问题?到目前为止我对它没有异议。

Edit.

编辑。

Ok, I have a problem because I am working with Arduino. It use memory and don't drop it, so you need to delete it after the use.

好的,我有个问题,因为我和Arduino一起工作。它使用内存,不删除,所以需要在使用后删除它。

#1


34  

You can do it with sprintf, but not alone (safely). On a sane system, use snprintf twice, once to find out the size to use and the second time to actually do it. This depends on snprintf returning the number of characters needed when it runs out of room. Linux, BSD, and C99-compatible systems do this; Windows typically does not. In the latter case, you'll need to allocate an initial buffer and allocate a bigger one if snprintf fails (in a loop until snprintf succeeds). But on C99, the following will work:

你可以用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);

However, for building SQL, it's far better to use prepared statements. They avoid SQL injection vulnerabilities (and frequently the need for sprintf). With them, you would prepare the statement "select key from answer where key = ? limit 5;", and then execute it with the parameter tmp. The SQL engine puts in the string and removes the need to make sure it's properly escaped first.

但是,对于构建SQL,最好使用准备好的语句。它们避免了SQL注入漏洞(并且经常需要sprintf)。使用它们,您将准备语句“select key from answer where key = ?”限制5;,然后使用参数tmp执行它。SQL引擎输入字符串,并消除了确保它首先正确转义的需要。

#2


8  

You want sprintf().

你想要sprintf()。

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

#3


6  

If you're using gnu or BSD libc you may be able to use asprintf, which allocates a buffer of the correct size automatically.

如果您正在使用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


1  

I am actually using sqlite3_bind_text to input my wildcard instead of generating through sprintf:

我实际上是在使用sqlite3_bind_text输入我的通配符,而不是通过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);

#5


0  

On windows you can use sprintf_s which adds buffer overflow protection like Michael E was saying.

在windows上,您可以使用sprintf_s来添加缓冲区溢出保护,就像Michael E所说的那样。

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

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

#6


-1  

The Michael Ekstrand code is good, but you will need to copy and paste it various times. I use this code in one function

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

Does it has problem with buffer overflow? Until now I don't have problem with it.

是否存在缓冲区溢出问题?到目前为止我对它没有异议。

Edit.

编辑。

Ok, I have a problem because I am working with Arduino. It use memory and don't drop it, so you need to delete it after the use.

好的,我有个问题,因为我和Arduino一起工作。它使用内存,不删除,所以需要在使用后删除它。