簡體   English   中英

Python ctypes:加載庫時OSError未定義符號

[英]Python ctypes : OSError undefined symbol when loading library

在Ubuntu 14.04中,我編寫了一個名為hash.c的C文件:

/* hash.c: hash table with linear probing */

typedef struct {
    void *key;
    void *value;
} ht_entry;

typedef struct {
    ht_entry *table;
    int len;
    int num_entries;
    int (*hash_fn)(void *key);
    int (*key_cmp)(void *k1, void *k2);
} hashtable;

並用

gcc -shared hash.c -o test.so -fPIC

之后,我嘗試在Python腳本中加載test.so(用於測試),但是出現以下錯誤:“ OSError:... / test.so:未定義的符號:hash_fn”

hash_fn是哈希表結構中的函數指針。 在文件的后面,函數多次引用了它。

我不明白為什么會發生此錯誤。 我已經Google搜索過,但所有其他情況都涉及C ++或包含。 就我而言,我只有1個C文件,僅包含stdio和stdlib。


這是全代碼。 當我注釋掉除hash_create和print_info之外的所有內容時,它將成功加載。 當我取消注釋find()時,會發生錯誤。 (print_info僅用於測試ctypes是否有效)

/* hash.c: hash table with linear probing */

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    void *key;
    void *value;
} ht_entry;

typedef struct {
    ht_entry *table;
    int len;
    int num_entries;
    int (*hash_fn)(void *key);
    int (*key_cmp)(void *k1, void *k2);
} hashtable;

static void close_gap(hashtable *ht, int i);
static int find(hashtable *ht, void *key);

hashtable* hash_create(int len, int (*hash_fn)(void*), int (*key_cmp)(void*, void*))
{
    hashtable* ht = (hashtable*) malloc(sizeof(hashtable));
    ht->len = len;
    ht->table = calloc(len, sizeof(ht_entry));  
    ht->hash_fn = hash_fn;
    ht->key_cmp = key_cmp;
    ht->table[0].key = 2;
    ht->table[0].value = 3;
    return ht;
}

void print_info(hashtable *ht)
{
    printf("%d, %d, %d\n", ht->len, ht->table[0].key, ht->table[0].value);
}

void* hash_retrieve(hashtable* ht, void *key)
{
    int i = find(ht, key);
    if(i < 0) {
        return NULL;
    }

    return ht->table[i].value;
}

void hash_insert(hashtable* ht, void *key, void *value)
{
    if(ht->num_entries == ht->len) {
        return;
    }

    int i = hash_fn(key) % ht->len;
    while(ht->table[i].key != NULL) {
        i = (i + i) % ht->len;
    }
    ht->table[i].key = key;
    ht->table[i].value = value;
}

void hash_remove(hashtable *ht, void *key)
{
    int i = find(ht, key);
    if(i < 0) {
        return;
    }   
    ht->table[i].key = 0;
    ht->table[i].value = 0;
    close_gap(ht, i);
}

static int find(hashtable *ht, void *key)
{
    int i = hash_fn(key) % ht->len;
    int num_checked = 0;
    while(ht->table[i].key && num_checked != ht->len) {
        if(!ht->key_cmp(ht->table[i].key, key)) {
            return i;
        }
        num_checked++;
        i = (i + i) % ht->len;
    }
    return -1;
}

static void close_gap(hashtable *ht, int i)
{
    int j = (i + 1) % ht->len;
    while(ht->table[j].key) {
        int loc = ht->hash_fn(ht->table[j].key);
        if((j > i && (loc <= i || loc > j)) || (j < i && (loc <= i && loc > j))) {
            ht->table[i] = ht->table[j];
            ht->table[j].key = 0;
            ht->table[j].value = 0;
            close_gap(ht, j);
            return;
        }
    }
}

當我使用您的編譯行時,會收到五個警告。 這里有幾個問題。 首先,您嘗試在多個位置將int分配給void * 這會引發警告,並且在運行時會崩潰,因為您要傳遞2和3作為地址。

第二,你在呼喚hash_fn在幾個地方,而不是ht->hash_fn 這會導致鏈接器錯誤,但是您應該考慮我的其他更改,否則它將在運行時使用SIGSEGV崩潰:

/* hash.c: hash table with linear probing */

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    void *key;
    void *value;
} ht_entry;

typedef struct {
    ht_entry *table;
    int len;
    int num_entries;
    int (*hash_fn)(void *key);
    int (*key_cmp)(void *k1, void *k2);
} hashtable;

static void close_gap(hashtable *ht, int i);
static int find(hashtable *ht, void *key);


hashtable* hash_create(int len, int (*hash_fn)(void*), int (*key_cmp)(void*, void*))
{
    hashtable* ht = (hashtable*) malloc(sizeof(hashtable));
    ht->len = len;
    ht->table = calloc(len, sizeof(ht_entry));
    ht->hash_fn = hash_fn;
    ht->key_cmp = key_cmp;

    // <<< Code changed here
    /*
    ht->table[0].key = 2;
    ht->table[0].value = 3;
    */

    {
        int *p = malloc(sizeof(int));
        *p = 2;
        ht->table[0].key = p;

        p = malloc(sizeof(int));
        *p = 3;
        ht->table[0].value = p;
    }
    // end of code change   

    return ht;
}

void print_info(hashtable *ht)
{
    // <<<<  Code changed
    printf("%d, %d, %d\n", ht->len,
           *(int *)ht->table[0].key, *(int *)ht->table[0].value);
}

void* hash_retrieve(hashtable* ht, void *key)
{
    int i = find(ht, key);
    if(i < 0) {
        return NULL;
    }

    return ht->table[i].value;
}

void hash_insert(hashtable* ht, void *key, void *value)
{
    if(ht->num_entries == ht->len) {
        return;
    }

    // <<<  Code changed
    int i = ht->hash_fn(key) % ht->len;

    while(ht->table[i].key != NULL) {
        i = (i + i) % ht->len;
    }
    ht->table[i].key = key;
    ht->table[i].value = value;
}

void hash_remove(hashtable *ht, void *key)
{
    int i = find(ht, key);
    if(i < 0) {
        return;
   ht->table[i].key = 0;
    ht->table[i].value = 0;
    close_gap(ht, i);
}

static int find(hashtable *ht, void *key)
{
    // <<<  Code changed
    int i = ht->hash_fn(key) % ht->len;

    int num_checked = 0;
    while(ht->table[i].key && num_checked != ht->len) {
        if(!ht->key_cmp(ht->table[i].key, key)) {
            return i;
        }
        num_checked++;
        i = (i + i) % ht->len;
    }
    return -1;
}


static void close_gap(hashtable *ht, int i)
{
    int j = (i + 1) % ht->len;
    while(ht->table[j].key) {
        int loc = ht->hash_fn(ht->table[j].key);
        if((j > i && (loc <= i || loc > j)) || (j < i && (loc <= i && loc > j))) {
            ht->table[i] = ht->table[j];
            ht->table[j].key = 0;
            ht->table[j].value = 0;
            close_gap(ht, j);
            return;
        }
    }
}

我只對錯誤和警告進行編碼,沒有檢查邏輯。 您將看到我已經使用mallockeyvalue分配內存。 顯然,您將需要對這兩個進行內存管理(即free() )。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM