Использование значения указателей void в качестве ключей в хеш-таблице

Мне нужно реализовать словарь, который использует произвольные указатели void в качестве ключей.

Чтобы сделать доступ O (1), я хотел бы хешировать значения самих указателей (а не данные, на которые они указывают).

Итак, например, предположим, что у меня есть void *key, и у меня уже есть общая хэш-функция unsigned int hash(const char *data, size_t len).

Правильно ли делать что-то вроде unsigned int keyhash = hash((char *)&key, sizeof key); для вычисления хеш-значения?

Кроме того, чтобы иметь дело с коллизиями, мне затем нужно было бы перебрать связанный список всех ключей, которые хешируются до одного и того же значения. Для этого позволит ли стандарт сравнивать void *key1, *key2 как key1 == key2; или как memcmp(&key1, &key2, sizeof (void *));?


person Tob Ernack    schedule 04.09.2017    source источник
comment
Я думаю, что sizeof key неправильно. Потому что это не размер контента.   -  person BLUEPIXY    schedule 04.09.2017
comment
Маловероятно, что &key, sizeof key верны. Возможно, но я в этом сомневаюсь. Если вы намеренно не хешируете значения void указателей (не то, что они указывают на, сами фактические адреса), делать то, что вы предлагаете, безусловно, неправильно.   -  person WhozCraig    schedule 04.09.2017
comment
Да, я намерен хешировать значения, а не данные, на которые они указывают.   -  person Tob Ernack    schedule 04.09.2017
comment
Тогда, сюрприз, это правильно =P   -  person WhozCraig    schedule 04.09.2017
comment
hash((char *)&key, sizeof key) выглядит именно так, как мне кажется.   -  person Steve Summit    schedule 04.09.2017
comment
Причина в том, что я хочу связать некоторые метаданные с определенными структурами, которые выделены в памяти. И я не могу добавить его к самим структурам, потому что данные могут быть разными для разных контекстов (и разных потоков).   -  person Tob Ernack    schedule 04.09.2017
comment
И я не уверен, что стандарт говорит об использовании == для сравнения указателей, если они не обязательно указывают на один и тот же массив.   -  person Tob Ernack    schedule 04.09.2017
comment
Указатели @TobErnack всегда можно сравнить с ==.   -  person Ajay Brahmakshatriya    schedule 04.09.2017
comment
Кроме того, вы можете показать больше кода? Как тело функции hash. Мы действительно не знаем, что вы делаете с data.   -  person Ajay Brahmakshatriya    schedule 04.09.2017
comment
Вопрос для меня немного неясен, но насколько я понимаю вопрос, эта часть - unsigned int keyhash = hash((char *)&key, sizeof key); - неверна. Я не думаю, что вы должны делать &key, так как вам не нужен адрес указателя void. Вам нужно значение, поэтому просто используйте key, то есть без & BTW: сравнение двух указателей void с использованием == — это нормально.   -  person 4386427    schedule 04.09.2017
comment
Вы можете преобразовать значения void * в uintptr_t, поскольку сравнения между значениями uintptr_t (целое число без знака) полностью определены, даже если сравнения между значениями void * не определены. Теоретически у вас может быть система без типа uintptr_t. Более прагматично, есть системы, в которых указатели на функции слишком велики, чтобы поместиться в любой указатель на объект (IBM AS/400 и последующие версии).   -  person Jonathan Leffler    schedule 04.09.2017


Ответы (1)


Насколько я понимаю, вы хотите хешировать значение указателя void. В таком случае этот код

unsigned int keyhash = hash((char *)&key, sizeof key);

неверно, поскольку вы передаете адрес указателя void (т.е. &key) вместо значения (т.е. просто key).

Взгляните на этот код:

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

int hash(const char *data, size_t len)
{
    // Dummy code ... just a print - no hash calculation
    printf("value of data %p with size %zu\n", (void*)data, len);
    return 0;
}

int main(void) {
    void* key;
    key = malloc(sizeof(int));
    printf("value of key %p\n", key);

    // First call using &key
    unsigned int keyhash1 = hash((char *)&key, sizeof key);

    // Second call using key (i.e. no &)
    unsigned int keyhash2 = hash((char *)key, sizeof key);

    free(key);

    return 0;
}

Выход может быть:

value of key 0x2b51dca5a010
value of data 0x7fffff6be5e8 with size 8
value of data 0x2b51dca5a010 with size 8

Как вы можете видеть, первый вызов функции не получает значение указателя на распределенный объект, т.е. первый вызов неверен. Второй вызов функции получает правильное значение.

Так что не надо нам &key - просто key

Кстати: сравнение двух указателей void с использованием == в порядке.

person 4386427    schedule 04.09.2017
comment
OP сказал, что хочет использовать указатели в качестве хеш-ключей, а не цели указателя. Использование &key правильно для этого использования. - person aghast; 04.09.2017
comment
@nos OP говорит, что хочет использовать значение указателя в качестве ключа, а не то, на что указывает указатель. Таким образом, хеш, который требует (указатель, len) на хешируемый объект, должен иметь указатель на указатель (& ключ), а не указатель на объект (ключ). - person aghast; 04.09.2017
comment
Все зависит от конкретной последовательности вызова функции hash(). Но учитывая, что ей передается указатель и длина, кажется вероятным, что хеш-функция обрабатывает полученный указатель как указатель на данные (переменного размера), подлежащие хэшированию. Если это так, передача указателя &key и размера sizeof(key) кажется правильной. - person Steve Summit; 04.09.2017