如何将 printf 存储到变量中?

发布于 2024-08-11 13:06:57 字数 228 浏览 3 评论 0原文

我想使用类似于 C 中 printf 的方法来存储格式化字符串。

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

后者显然是一个错误。

I want to store a formatted string using something similar to what printf does in 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

末骤雨初歇 2024-08-18 13:06:57

您可以使用 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,最好使用 准备好的声明。它们避免了 SQL 注入漏洞(并且经常需要 sprintf)。使用它们,您可以准备语句“select key from answer where key = ? limit 5;”,然后使用参数tmp执行它。 SQL 引擎放入字符串并消除首先确保其正确转义的需要。

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:

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.

傲娇萝莉攻 2024-08-18 13:06:57

您需要sprintf()

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

You want sprintf().

char *sqlAnswers = malloc(SIZE_TO_HOLD_FINAL_STRING);
sprintf(sqlAnswers, "select key from answer WHERE key = %s LIMIT 5;", tmp);
过潦 2024-08-18 13:06:57

如果您使用的是 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);

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

#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);
開玄 2024-08-18 13:06:57

我实际上使用 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);

I am actually using sqlite3_bind_text to input my wildcard instead of generating through 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);
寄与心 2024-08-18 13:06:57

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

是否存在缓冲区溢出问题?到目前为止我还没有遇到任何问题。

编辑。

好吧,我有一个问题,因为我正在使用 Arduino。它使用内存并且不会丢弃它,因此使用后需要删除它。

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

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.

鸩远一方 2024-08-18 13:06:57

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

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

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

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文