【问题标题】:GDBM object passed via void pointer is lost/corrupted通过 void 指针传递的 GDBM 对象丢失/损坏
【发布时间】:2013-06-28 00:52:14
【问题描述】:

我有一个程序可以将 GDBM 或 Kyoto Cabinet 用作 DBM 库。我编写了一些函数来抽象出两者之间的差异,并且我传递了 void 指针来代替数据库文件(在 GDBM 的情况下为GDBM_FILE,在京都内阁的情况下为KCDB *)。 KC 的一切工作正常,但是当我尝试使用 GDBM 后端时,数据库在将它传递给不同的函数时会以某种方式“丢失”。当我尝试强制转换指针并取消引用它,然后将其传递给其中一个 GDBM 函数时,它会出现段错误,并且在调试器中它会抱怨 db 文件不存在。

这里有一些可以重现问题的代码:

#include <gdbm.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>

void *
dbopen (void)
{
  printf ("opening\n");
  GDBM_FILE database = gdbm_open ("test.db", 512, GDBM_WRCREAT,
                                  S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, NULL);
  if (!database)
    {
      printf ("cannot open database\n");
      return NULL;
    }
  void *db = &database;
  return db;
}

void
dbclose (void *db, void *foo)
{
  printf ("%d\n", *(int *)foo);
  GDBM_FILE database = *(GDBM_FILE *)db;
  if (!database)
    {
      printf ("database lost\n");
      return;
    }
  printf ("closing\n");
  gdbm_close (database);
  return;
}

void
fun (void *db, void *foo)
{
  GDBM_FILE database = *(GDBM_FILE *)db;
  datum key, value;
  int bar = *(int *)foo;  /* and yet, if I remove this line and the next */
  printf ("%d\n", bar);   /* one, it works! */
  printf ("%d\n", *(int *)foo);
  if (!database)
    printf ("no db?\n");
  key.dptr = "baz";
  key.dsize = 4;
  value.dptr = "quux";
  value.dsize = 4;
  printf ("storing\n");
  gdbm_store (database, key, value, GDBM_REPLACE);
  printf ("all done\n");
  return;
}

int
main (void)
{
  int foo = 5;
  void *dbp = dbopen ();
  void *foop = &foo;
  fun (dbp, foop);
  dbclose (dbp, foop);
}

当我运行该代码时,它在调用gdbm_close() 时出现“找不到文件”错误。正如 cmets 所指出的,如果我没有明确地将另一个 void 指针存储到一个 int,那么程序运行得很好。

在我的实际程序中,当我调用 gdbm_store() 时它会“丢失”,这是我正在使用的唯一 void 指针(在这个测试程序中,foo 指针应该只是一个健全性检查) .

我确信在 C 中的内存分配变幻莫测中有些东西我忘记了或不理解。当引用 int 的 void 指针没有时,为什么引用 GDBM 数据库的 void 指针会丢失/损坏?为什么,当我不尝试将取消引用的 void 指针 foo 存储到 int 时,它会突然起作用吗?

【问题讨论】:

    标签: c void-pointers gdbm


    【解决方案1】:

    您的问题在于获取从gdbm_open 返回的指针的地址,而不是它的值。令人困惑的部分来自GDBM_FILE 的定义——它是一个指向结构的指针:

    typedef struct {int dummy[10];} *GDBM_FILE;
    

    你得到它的地址,也就是指针所在的位置,而不是指针值:

    void *db = &database;
    

    问题可以通过将转换行替换为:

    void *db = (void *)database;
    

    GDBM_FILE database = (GDBM_FILE)db;
    

    【讨论】:

    • 啊,这一切都清楚了,谢谢!注意最后一行应该是GDBM_FILE database = (GDBM_FILE)db;,否则它是一个双指针。
    • 另外,我想也可以是void *db = database
    • typedef 指向东西的指针太乱了,我和你陷入了同样的陷阱:)
    • 恕我直言,演员阵容更具可读性。另一方面,如果你重构代码并且演员隐藏了立即出现的问题,那么额外的演员可能会在未来导致问题......
    猜你喜欢
    • 2019-12-28
    • 2013-06-05
    • 1970-01-01
    • 1970-01-01
    • 2016-11-19
    • 2017-04-05
    • 2021-06-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多