2013-06-30 15 views
1

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) :

다음은 문제를 재현 할 수있는 몇 가지 코드입니다. 주석이 지적한 것처럼, 명시 적으로 다른 void 포인터를 int에 저장하지 않으면 프로그램이 정상적으로 실행됩니다.

내 실제 프로그램에서는 gdbm_store()을 호출하면 "손실"되고,이 테스트 프로그램에서는 사용중인 유일한 무효 포인터입니다 (foo 포인터가 온전함 검사로만 사용됨).

나는 잊어 버리고있는 C에서의 메모리 할당에 관한 무언가가있을 것이라고 확신한다. int를 참조하는 void 포인터가 GDBM 데이터베이스를 참조하는 void 포인터가 왜 손실되거나 손상됩니까? 왜, dereferenced void 포인터 foo을 int에 저장하려고 시도하지 않을 때, 갑자기 작동합니까?

답변

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; 
+0

감사합니다. 마지막 줄은'GDBM_FILE database = (GDBM_FILE) db; '이어야한다. 그렇지 않으면 이중 포인터이기 때문이다. –

+1

또한 'void * db = database' 일 수도 있습니다. –

+0

그 물건에 typedef 포인터가 너무 지저분 해, 나는 너와 같은 함정에 빠졌다 : – bbonev