【问题标题】:libmysql: warning: address of local variable ‘rows’ returned (C++/C)libmysql:警告:返回的局部变量“行”的地址(C++/C)
【发布时间】:2019-10-11 06:24:28
【问题描述】:

我正在使用 g++。

为了方便使用 libmysql,实现了一些包装器。还制作了与 C/C++ 兼容的代码。

static MYSQL_RES *db_query(MYSQL *db, const char *query, va_list params) {
    char q[500];
    vsprintf(q, query, params);
    va_end(params);
    if (mysql_query(db, q)) {
        fprintf(stderr, "%s\n", mysql_error(db));
        return NULL;
    }

    MYSQL_RES *res = mysql_use_result(db);
    return res;
}

MYSQL_ROW* db_query_all(MYSQL *db, const char* query, ...) {
        va_list params;
    MYSQL_RES *res = db_query(db, query, params);

    int count = mysql_num_rows(res);

    MYSQL_ROW rows[count];
    for (int i = 0; i<count; i++) 
    {
        rows[i] = mysql_fetch_row(res);
    }

    mysql_free_result(res);
    return rows;
}

并在编译期间收到警告:

warning: address of local variable ‘rows’ returned [-Wreturn-local-addr]
     MYSQL_ROW rows[count];

请帮我找出问题所在。我无法搜索与我的特定案例相关的内容。

【问题讨论】:

  • MYSQL_ROW rows[count];会在栈上分配,需要通过malloc/calloc在堆上分配,如果还在栈上,则变量的内容是未定义的一旦你退出函数

标签: c++ c libmysql


【解决方案1】:

一种更 C++ 的方法是定义一个 movable 缓冲区类型:

struct Buf {
  Buf(size_t size) : mPtr(std::make_unique<MYSQL_ROW[]>(size)), mSize(size) {}

  std::unique_ptr<MYSQL_ROW[]> mPtr;
  size_t mSize;
};

然后你可以这样实现函数:

Buf db_query_all(MYSQL *db, const char* query, ...) {
        va_list params;
    MYSQL_RES *res = db_query(db, query, params);

    int count = mysql_num_rows(res);

    Buf rows(count);
    for (int i = 0; i<count; i++) 
    {
        rows.mPtr[i] = mysql_fetch_row(res);
    }

    mysql_free_result(res);
    return std::move(rows);
}

这种方法的最大好处是您不必手动处理内存。

【讨论】:

  • 哇。这看起来很酷。但是你为什么不使用std::string tho?无论如何,我需要与 C 兼容的代码才能获得更好的性能,但谢谢你也分享了这个 sn-p
  • “C 兼容代码”不会自动为您提供更好的性能。
【解决方案2】:

rowsdb_query_all 函数的本地数组,一旦控制退出函数就会被销毁,因此返回它的引用是未定义的行为。

您可以动态分配内存并返回对它的引用。

MYSQL_ROW* db_query_all(MYSQL *db, const char* query, ...) {
        va_list params;
    MYSQL_RES *res = db_query(db, query, params);

    int count = mysql_num_rows(res);

    MYSQL_ROW *rows = malloc(sizeof(*rows)*count);
    for (int i = 0; i<count; i++) 
    {
        rows[i] = mysql_fetch_row(res);
    }

    mysql_free_result(res);
    return rows;
}

请注意,一旦完成处理,您需要free 内存。

【讨论】:

  • 啊……我明白了……谢谢你的代码。所以你在malloc 之前忘记了(MYSQL_ROW *),因为C++......但我会测试......再次感谢
  • 我在考虑C :D
  • 由于问题是在 C++ 上下文中提出的,因此您应该使用 new/delete 而不是 malloc()/free()。
【解决方案3】:

您的错误信息来自这一行:

MYSQL_ROW rows[count];

这意味着rows 将被分配到堆栈上,这意味着一旦你的函数退出,你的变量的内容将是未定义的。

你需要:

  • 在堆上分配变量(推荐)
MYSQL_ROW rows[] = calloc(count,sizeof(MYSQL_ROW));

一旦你不再需要结果,别忘了free

  • 从上游传递行作为参数
    这将需要您在另一个步骤中获得计数

【讨论】:

  • 是否需要使用calloc 而不是malloc。我基本上知道区别,但是这个特殊的东西呢?
  • 没有真正的区别,您可以通过使用malloc 来获得更多性能,因为calloc 正在将分配的内存归零。
  • 由于问题是在 C++ 上下文中提出的,因此您应该使用 new/delete 而不是 malloc()/free()。
  • @Pibben 我询问了 C/C++ 上下文。这意味着我为具有更严格规则的 C++ 编译器编写 C 程序。我喜欢我最终完全重构为 C++ 的差距,但现在我喜欢使用 C 来代替:)
  • @Pibben 公平地说,由于 C 标签,我从 C 的角度回答
猜你喜欢
  • 2011-10-17
  • 2013-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-13
  • 2019-06-15
  • 2015-04-25
相关资源
最近更新 更多