GDBM 또는 교토 캐비넷 중 하나를 DBM 라이브러리로 사용할 수있는 프로그램이 있습니다. 두 함수의 차이점을 추상화하는 함수를 작성했습니다. 데이터베이스 파일 대신에 void 포인터를 사용합니다 (GDBM의 경우 GDBM_FILE
, 교토 캐비닛의 경우 KCDB *
). KC의 모든 것이 잘 작동하지만, GDBM 백엔드를 사용하려고하면 데이터베이스가 어떻게해서 다른 기능으로 전달되는지 "손실"됩니다. 포인터를 캐스팅하고 역 참조를 시도한 다음 GDBM 함수 중 하나에 전달하면 segfaults가 발생하고 디버거에서는 존재하지 않는 db 파일에 대해 불평합니다. , 내가 그 코드를 실행하면void 포인터를 통해 전달 된 GDBM 객체가 손실/손상되었습니다.
#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()
에 대한 호출에서 "파일을 찾을 수 없습니다"오류와 함께 세그먼테이션 폴트 (segfault) :
내 실제 프로그램에서는 gdbm_store()
을 호출하면 "손실"되고,이 테스트 프로그램에서는 사용중인 유일한 무효 포인터입니다 (foo
포인터가 온전함 검사로만 사용됨).
나는 잊어 버리고있는 C에서의 메모리 할당에 관한 무언가가있을 것이라고 확신한다. int를 참조하는 void 포인터가 GDBM 데이터베이스를 참조하는 void 포인터가 왜 손실되거나 손상됩니까? 왜, dereferenced void 포인터 foo
을 int에 저장하려고 시도하지 않을 때, 갑자기 작동합니까?
감사합니다. 마지막 줄은'GDBM_FILE database = (GDBM_FILE) db; '이어야한다. 그렇지 않으면 이중 포인터이기 때문이다. –
또한 'void * db = database' 일 수도 있습니다. –
그 물건에 typedef 포인터가 너무 지저분 해, 나는 너와 같은 함정에 빠졌다 : – bbonev