通过void指针传递的GDBM对象丢失/损坏

时间:2013-06-30 22:15:27

标签: c void-pointers gdbm

我有一个程序可以使用GDBM或Kyoto Cabinet作为DBM库。我已经编写了一些函数来抽象出两者之间的区别,并且我传递了无效指针来代替数据库文件(在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()时出现“找不到文件”错误。正如注释所示,如果我没有将其他void指针显式存储到int,那么程序运行就好了。

在我的实际程序中,当我调用gdbm_store()时,它会“丢失”,并且它是我正在使用的唯一无效指针(在此测试程序中,foo指针应该是理智检查。)

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

1 个答案:

答案 0 :(得分:0)

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

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

你得到它的地址,即指针的位置,而不是指针值:

void *db = &database;

可以通过以下方式替换转换行来解决问题:

void *db = (void *)database;

GDBM_FILE database = (GDBM_FILE)db;