libmysql:警告:返回局部变量“行”的地址 (C++/C)

libmysql: warning: address of local variable ‘rows’ returned (C++/C)

我正在使用 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];

请帮我找出问题所在。我无法 google 与我的具体情况相关的内容。

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

您可以动态分配内存并 return 引用它。

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内存完成处理。

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

MYSQL_ROW rows[count];

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

您需要:

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

不要忘记free一旦你不再需要结果

  • 将来自上游的行作为参数传递
    这将需要您在另一步中获得计数

一种更 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);
}

这种方法的一大优点是您不必进行手动内存处理。