Python ctypes:加载库时OSError未定义的符号

时间:2015-07-06 07:21:25

标签: python c ctypes

在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(用于测试),但是我收到了以下错误:&#34; OSError:... / test.so:undefined symbol:hash_fn&#34; < / p>

hash_fn是哈希表结构中的函数指针。它稍后会被文件中的函数引用多次。

我不明白为什么会发生这种错误。我用谷歌搜索,但所有其他情况要么涉及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;
        }
    }
}

1 个答案:

答案 0 :(得分:2)

当我使用你的编译行时,我收到五个警告。这里有几个问题。首先,您要尝试在多个位置为if ($_POST['code'] == '1234'){ header("Location: redirect_to_me.php"); } 分配int。这引发了一个警告,它会在运行时崩溃,因为你传递2和3作为地址。

其次,您在几个地方而不是void *呼叫hash_fn。这会导致链接器错误,但您应该考虑我的其他更改,否则它将在运行时使用SIGSEGV崩溃:

ht->hash_fn

我只围绕错误和警告编码,我没有检查逻辑。您会看到我已使用/* 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; } } } mallockey分配内存。显然,你需要对这两者进行内存管理(即value)。